|
// 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.Linq;
using Microsoft.CodeAnalysis.CSharp.Symbols;
using Microsoft.CodeAnalysis.CSharp.Symbols.Metadata.PE;
using Microsoft.CodeAnalysis.CSharp.Symbols.Retargeting;
using Microsoft.CodeAnalysis.CSharp.Syntax;
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
{
public class RefFieldTests : CSharpTestBase
{
private static string IncludeExpectedOutput(string expectedOutput) => ExecutionConditionUtil.IsMonoOrCoreClr ? expectedOutput : null;
[CombinatorialData]
[Theory]
public void LanguageVersionDiagnostics(bool useCompilationReference)
{
var sourceA =
@"public ref struct S<T>
{
public ref T F1;
public ref readonly T F2;
public S(ref T t)
{
F1 = ref t;
F2 = ref t;
}
S(object unused, T t0)
{
this = default;
this = new S<T>();
this = new S<T> { F1 = t0 };
}
static void M1(T t1)
{
S<T> s1;
s1 = default;
s1 = new S<T>();
s1 = new S<T> { F1 = t1 };
}
static void M2(ref T t2)
{
scoped S<T> s2;
s2 = new S<T>(ref t2);
s2 = new S<T> { F1 = t2 };
}
static void M3(S<T> s3)
{
var other = s3;
M1(s3.F1);
M1(s3.F2);
M2(ref s3.F1);
}
void M4(T t4)
{
this = default;
this = new S<T>();
this = new S<T> { F1 = t4 };
}
void M5(S<T> s5)
{
var other = this;
M1(F1);
M1(F2);
M2(ref F1);
M1(this.F1);
M1(this.F2);
M2(ref this.F1);
M1(s5.F1);
M1(s5.F2);
M2(ref s5.F1);
}
}";
var comp = CreateCompilation(sourceA, parseOptions: TestOptions.Regular10, targetFramework: TargetFramework.Net70);
comp.VerifyEmitDiagnostics(
// (3,12): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater.
// public ref T F1;
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "ref T").WithArguments("ref fields", "11.0").WithLocation(3, 12),
// (4,12): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater.
// public ref readonly T F2;
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "ref readonly T").WithArguments("ref fields", "11.0").WithLocation(4, 12),
// (25,9): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater.
// scoped S<T> s2;
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "scoped").WithArguments("ref fields", "11.0").WithLocation(25, 9));
comp = CreateCompilation(sourceA, targetFramework: TargetFramework.Net70);
comp.VerifyEmitDiagnostics();
var refA = AsReference(comp, useCompilationReference);
var sourceB =
@"class Program
{
static void M1<T>(T t)
{
S<T> s1;
s1 = default;
s1 = new S<T>();
s1 = new S<T> { F1 = t };
}
static void M2<T>(ref T t)
{
scoped S<T> s2;
s2 = new S<T>(ref t);
s2 = new S<T> { F1 = t };
}
static void M3<T>(S<T> s)
{
var s3 = s;
M1(s.F1);
M1(s.F2);
M2(ref s.F1);
}
}";
comp = CreateCompilation(sourceB, references: new[] { refA }, parseOptions: TestOptions.Regular10, targetFramework: TargetFramework.Net70);
comp.VerifyEmitDiagnostics(
// (8,25): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater.
// s1 = new S<T> { F1 = t };
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "F1").WithArguments("ref fields", "11.0").WithLocation(8, 25),
// (12,9): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater.
// scoped S<T> s2;
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "scoped").WithArguments("ref fields", "11.0").WithLocation(12, 9),
// (14,25): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater.
// s2 = new S<T> { F1 = t };
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "F1").WithArguments("ref fields", "11.0").WithLocation(14, 25),
// (19,12): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater.
// M1(s.F1);
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "s.F1").WithArguments("ref fields", "11.0").WithLocation(19, 12),
// (20,12): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater.
// M1(s.F2);
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "s.F2").WithArguments("ref fields", "11.0").WithLocation(20, 12),
// (21,16): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater.
// M2(ref s.F1);
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "s.F1").WithArguments("ref fields", "11.0").WithLocation(21, 16));
VerifyFieldSymbol(comp.GetMember<FieldSymbol>("S.F1"), "ref T S<T>.F1", RefKind.Ref, new string[0]);
VerifyFieldSymbol(comp.GetMember<FieldSymbol>("S.F2"), "ref readonly T S<T>.F2", RefKind.RefReadOnly, new string[0]);
comp = CreateCompilation(sourceB, references: new[] { refA }, parseOptions: TestOptions.Regular11, targetFramework: TargetFramework.Net70);
comp.VerifyEmitDiagnostics();
VerifyFieldSymbol(comp.GetMember<FieldSymbol>("S.F1"), "ref T S<T>.F1", RefKind.Ref, new string[0]);
VerifyFieldSymbol(comp.GetMember<FieldSymbol>("S.F2"), "ref readonly T S<T>.F2", RefKind.RefReadOnly, new string[0]);
}
[CombinatorialData]
[Theory]
public void RefField(bool useCompilationReference)
{
var sourceA =
@"public ref struct S<T>
{
public ref T F;
public S(ref T t) { F = ref t; }
}";
var comp = CreateCompilation(sourceA, parseOptions: TestOptions.Regular10, targetFramework: TargetFramework.Net70);
comp.VerifyEmitDiagnostics(
// (3,12): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater.
// public ref T F;
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "ref T").WithArguments("ref fields", "11.0").WithLocation(3, 12));
VerifyFieldSymbol(comp.GetMember<FieldSymbol>("S.F"), "ref T S<T>.F", RefKind.Ref, new string[0]);
comp = CreateCompilation(sourceA, targetFramework: TargetFramework.Net70);
comp.VerifyEmitDiagnostics();
var refA = AsReference(comp, useCompilationReference);
VerifyFieldSymbol(comp.GetMember<FieldSymbol>("S.F"), "ref T S<T>.F", RefKind.Ref, new string[0]);
var sourceB =
@"using System;
class Program
{
static void Main()
{
int x = 1;
var s = new S<int>(ref x);
s.F = 2;
Console.WriteLine(s.F);
Console.WriteLine(x);
x = 3;
Console.WriteLine(s.F);
Console.WriteLine(x);
}
}";
comp = CreateCompilation(sourceB, references: new[] { refA }, parseOptions: TestOptions.Regular10, targetFramework: TargetFramework.Net70);
comp.VerifyEmitDiagnostics(
// (8,9): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater.
// s.F = 2;
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "s.F").WithArguments("ref fields", "11.0").WithLocation(8, 9),
// (9,27): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater.
// Console.WriteLine(s.F);
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "s.F").WithArguments("ref fields", "11.0").WithLocation(9, 27),
// (12,27): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater.
// Console.WriteLine(s.F);
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "s.F").WithArguments("ref fields", "11.0").WithLocation(12, 27));
VerifyFieldSymbol(comp.GetMember<FieldSymbol>("S.F"), "ref T S<T>.F", RefKind.Ref, new string[0]);
comp = CreateCompilation(sourceB, references: new[] { refA }, parseOptions: TestOptions.Regular11, options: TestOptions.ReleaseExe, targetFramework: TargetFramework.Net70);
var verifier = CompileAndVerify(comp, verify: Verification.Skipped, expectedOutput: IncludeExpectedOutput(
@"2
2
3
3
"));
comp = (CSharpCompilation)verifier.Compilation;
VerifyFieldSymbol(comp.GetMember<FieldSymbol>("S.F"), "ref T S<T>.F", RefKind.Ref, new string[0]);
}
[CombinatorialData]
[Theory]
public void RefReadonlyField(bool useCompilationReference)
{
var sourceA =
@"public ref struct S<T>
{
public ref readonly T F;
public S(in T t)
{
F = ref t;
}
}";
var comp = CreateCompilation(sourceA, parseOptions: TestOptions.Regular10, targetFramework: TargetFramework.Net70);
comp.VerifyEmitDiagnostics(
// (3,12): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater.
// public ref readonly T F;
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "ref readonly T").WithArguments("ref fields", "11.0").WithLocation(3, 12));
VerifyFieldSymbol(comp.GetMember<FieldSymbol>("S.F"), "ref readonly T S<T>.F", RefKind.RefReadOnly, new string[0]);
comp = CreateCompilation(sourceA, targetFramework: TargetFramework.Net70);
comp.VerifyEmitDiagnostics();
var refA = AsReference(comp, useCompilationReference);
VerifyFieldSymbol(comp.GetMember<FieldSymbol>("S.F"), "ref readonly T S<T>.F", RefKind.RefReadOnly, new string[0]);
var sourceB =
@"using System;
class A
{
internal int G;
}
class Program
{
static void Main()
{
A a = new A();
a.G = 1;
var s = new S<A>(in a);
s.F.G = 2;
Console.WriteLine(s.F.G);
Console.WriteLine(a.G);
a.G = 3;
Console.WriteLine(s.F.G);
Console.WriteLine(a.G);
}
}";
comp = CreateCompilation(sourceB, references: new[] { refA }, parseOptions: TestOptions.Regular10, targetFramework: TargetFramework.Net70);
comp.VerifyEmitDiagnostics(
// (13,9): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater.
// s.F.G = 2;
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "s.F").WithArguments("ref fields", "11.0").WithLocation(13, 9),
// (14,27): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater.
// Console.WriteLine(s.F.G);
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "s.F").WithArguments("ref fields", "11.0").WithLocation(14, 27),
// (17,27): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater.
// Console.WriteLine(s.F.G);
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "s.F").WithArguments("ref fields", "11.0").WithLocation(17, 27));
VerifyFieldSymbol(comp.GetMember<FieldSymbol>("S.F"), "ref readonly T S<T>.F", RefKind.RefReadOnly, new string[0]);
comp = CreateCompilation(sourceB, references: new[] { refA }, parseOptions: TestOptions.Regular11, options: TestOptions.ReleaseExe, targetFramework: TargetFramework.Net70);
var verifier = CompileAndVerify(comp, verify: Verification.Skipped, expectedOutput: IncludeExpectedOutput(
@"2
2
3
3
"));
comp = (CSharpCompilation)verifier.Compilation;
VerifyFieldSymbol(comp.GetMember<FieldSymbol>("S.F"), "ref readonly T S<T>.F", RefKind.RefReadOnly, new string[0]);
}
[Fact]
public void SubstitutedField()
{
var sourceA =
@".class public A<T>
{
.field public !0& modopt(object) modopt(int8) F
}";
var refA = CompileIL(sourceA);
var sourceB =
@"#pragma warning disable 169
class B
{
static A<int> A;
}";
var comp = CreateCompilation(sourceB, new[] { refA });
comp.VerifyEmitDiagnostics();
CompileAndVerify(comp);
var field = (SubstitutedFieldSymbol)comp.GetMember<FieldSymbol>("B.A").Type.GetMember("F");
VerifyFieldSymbol(field, "ref modopt(System.SByte) modopt(System.Object) System.Int32 A<System.Int32>.F", RefKind.Ref, new[] { "System.SByte", "System.Object" });
}
[Fact]
public void RetargetingField()
{
var sourceA =
@"public ref struct A
{
public ref readonly int F;
}
";
var comp = CreateCompilation(sourceA, targetFramework: TargetFramework.Mscorlib40);
var refA = comp.ToMetadataReference();
var sourceB =
@"#pragma warning disable 169
ref struct B
{
A A;
}";
comp = CreateCompilation(sourceB, new[] { refA }, targetFramework: TargetFramework.Mscorlib45);
comp.VerifyEmitDiagnostics();
CompileAndVerify(comp, verify: Verification.Skipped);
var field = (RetargetingFieldSymbol)comp.GetMember<FieldSymbol>("B.A").Type.GetMember("F");
// Currently, source symbols cannot declare RefCustomModifiers. If that
// changes, update this test to verify retargeting of RefCutomModifiers.
VerifyFieldSymbol(field, "ref readonly System.Int32 A.F", RefKind.RefReadOnly, new string[0]);
}
[WorkItem(64682, "https://github.com/dotnet/roslyn/issues/64682")]
[Fact]
public void RefFieldInNonRefStruct()
{
var sourceA =
@".class public A<T>
{
.field public !0& F1
}
.class public sealed S extends [mscorlib]System.ValueType
{
.field public int32& F2
}";
var refA = CompileIL(sourceA);
var sourceB =
@"class Program
{
static ref int F1(ref A<int> a) => ref a.F1; // 1
static ref int F2(ref S s) => ref s.F2; // 2
}";
// https://github.com/dotnet/roslyn/issues/64682: Should report use-site errors.
var comp = CreateCompilation(sourceB, new[] { refA }, targetFramework: TargetFramework.Net70);
comp.VerifyEmitDiagnostics();
CompileAndVerify(comp, verify: Verification.Skipped);
}
[Fact]
public void RefAndReadonlyRefStruct_01()
{
var source =
@"#pragma warning disable 169
ref struct A
{
ref int A1;
ref readonly int A2;
readonly ref int A3;
readonly ref readonly int A4;
}
readonly ref struct B
{
ref int B1;
ref readonly int B2;
readonly ref int B3;
readonly ref readonly int B4;
}";
var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70);
comp.VerifyEmitDiagnostics(
// (11,13): error CS8340: Instance fields of readonly structs must be readonly.
// ref int B1;
Diagnostic(ErrorCode.ERR_FieldsInRoStruct, "B1").WithLocation(11, 13),
// (12,22): error CS8340: Instance fields of readonly structs must be readonly.
// ref readonly int B2;
Diagnostic(ErrorCode.ERR_FieldsInRoStruct, "B2").WithLocation(12, 22));
}
/// <summary>
/// ref readonly fields emitted as initonly.
/// ref readonly fields emitted with System.Runtime.CompilerServices.IsReadOnlyAttribute.
/// </summary>
[Fact]
public void RefAndReadonlyRefStruct_02()
{
var source =
@"#pragma warning disable 169
ref struct A
{
ref int A1;
ref readonly int A2;
readonly ref int A3;
readonly ref readonly int A4;
}
readonly ref struct B
{
readonly ref int B3;
readonly ref readonly int B4;
}";
var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70);
comp.VerifyEmitDiagnostics();
var verifier = CompileAndVerify(comp, verify: Verification.Skipped);
verifier.VerifyTypeIL("A",
@".class private sequential ansi sealed beforefieldinit A
extends [System.Runtime]System.ValueType
{
.custom instance void [System.Runtime]System.Runtime.CompilerServices.IsByRefLikeAttribute::.ctor() = (
01 00 00 00
)
.custom instance void [System.Runtime]System.ObsoleteAttribute::.ctor(string, bool) = (
01 00 52 54 79 70 65 73 20 77 69 74 68 20 65 6d
62 65 64 64 65 64 20 72 65 66 65 72 65 6e 63 65
73 20 61 72 65 20 6e 6f 74 20 73 75 70 70 6f 72
74 65 64 20 69 6e 20 74 68 69 73 20 76 65 72 73
69 6f 6e 20 6f 66 20 79 6f 75 72 20 63 6f 6d 70
69 6c 65 72 2e 01 00 00
)
.custom instance void [System.Runtime]System.Runtime.CompilerServices.CompilerFeatureRequiredAttribute::.ctor(string) = (
01 00 0a 52 65 66 53 74 72 75 63 74 73 00 00
)
// Fields
.field private int32& A1
.field private int32& A2
.custom instance void [System.Runtime]System.Runtime.CompilerServices.IsReadOnlyAttribute::.ctor() = (
01 00 00 00
)
.field private initonly int32& A3
.field private initonly int32& A4
.custom instance void [System.Runtime]System.Runtime.CompilerServices.IsReadOnlyAttribute::.ctor() = (
01 00 00 00
)
} // end of class A
");
verifier.VerifyTypeIL("B",
@".class private sequential ansi sealed beforefieldinit B
extends [System.Runtime]System.ValueType
{
.custom instance void [System.Runtime]System.Runtime.CompilerServices.IsByRefLikeAttribute::.ctor() = (
01 00 00 00
)
.custom instance void [System.Runtime]System.ObsoleteAttribute::.ctor(string, bool) = (
01 00 52 54 79 70 65 73 20 77 69 74 68 20 65 6d
62 65 64 64 65 64 20 72 65 66 65 72 65 6e 63 65
73 20 61 72 65 20 6e 6f 74 20 73 75 70 70 6f 72
74 65 64 20 69 6e 20 74 68 69 73 20 76 65 72 73
69 6f 6e 20 6f 66 20 79 6f 75 72 20 63 6f 6d 70
69 6c 65 72 2e 01 00 00
)
.custom instance void [System.Runtime]System.Runtime.CompilerServices.CompilerFeatureRequiredAttribute::.ctor(string) = (
01 00 0a 52 65 66 53 74 72 75 63 74 73 00 00
)
.custom instance void [System.Runtime]System.Runtime.CompilerServices.IsReadOnlyAttribute::.ctor() = (
01 00 00 00
)
// Fields
.field private initonly int32& B3
.field private initonly int32& B4
.custom instance void [System.Runtime]System.Runtime.CompilerServices.IsReadOnlyAttribute::.ctor() = (
01 00 00 00
)
} // end of class B
");
}
[Fact]
public void TupleField()
{
var sourceA =
@".class public sealed System.ValueTuple`2<T1, T2> extends [mscorlib]System.ValueType
{
.field public !T1& Item1
.field public !T2& modopt(int8) modopt(object) Item2
}";
var refA = CompileIL(sourceA);
var sourceB =
@"class B
{
static (int, object) F() => default;
}";
var comp = CreateCompilation(sourceB, targetFramework: TargetFramework.Mscorlib40, references: new[] { refA });
comp.VerifyEmitDiagnostics();
var tupleType = (NamedTypeSymbol)comp.GetMember<MethodSymbol>("B.F").ReturnType;
VerifyFieldSymbol(tupleType.GetField("Item1"), "ref System.Int32 (System.Int32, System.Object).Item1", RefKind.Ref, new string[0] { });
VerifyFieldSymbol(tupleType.GetField("Item2"), "ref modopt(System.Object) modopt(System.SByte) System.Object (System.Int32, System.Object).Item2", RefKind.Ref, new[] { "System.Object", "System.SByte" });
}
[ConditionalFact(typeof(WindowsDesktopOnly), Reason = ConditionalSkipReason.NoPiaNeedsDesktop)]
public void EmbeddedField()
{
var sourceA =
@".assembly extern mscorlib { .ver 4:0:0:0 .publickeytoken = (B7 7A 5C 56 19 34 E0 89) }
.assembly A
{
.custom instance void [mscorlib]System.Runtime.InteropServices.ImportedFromTypeLibAttribute::.ctor(string) = {string('_.dll')}
.custom instance void [mscorlib]System.Runtime.InteropServices.GuidAttribute::.ctor(string) = {string('EE8A431D-7D0C-4E13-80C7-52B9C93B9B76')}
}
.class public sealed S extends [mscorlib]System.ValueType
{
.field public int32& modopt(object) modopt(int32) F
}";
var refA = CompileIL(sourceA, prependDefaultHeader: false, embedInteropTypes: true);
var sourceB =
@"class Program
{
static void Main()
{
F(new S());
}
static void F(object o)
{
}
}";
var comp = CreateCompilation(sourceB, references: new[] { refA, CSharpRef });
var refB = comp.EmitToImageReference();
comp = CreateCompilation("", new[] { refB });
var module = (PEModuleSymbol)comp.GetReferencedAssemblySymbol(refB).Modules[0];
// Read from metadata directly to inspect the embedded type.
var decoder = new MetadataDecoder(module);
var reader = module.Module.MetadataReader;
var fieldHandle = reader.FieldDefinitions.Single(handle => reader.GetString(reader.GetFieldDefinition(handle).Name) == "F");
var fieldInfo = decoder.DecodeFieldSignature(fieldHandle);
Assert.True(fieldInfo.IsByRef);
Assert.Equal(new[] { "System.Int32", "System.Object" }, fieldInfo.RefCustomModifiers.SelectAsArray(m => m.Modifier.ToTestDisplayString()));
}
[Fact]
public void FixedField_01()
{
var source =
@"unsafe ref struct S
{
public fixed ref int F1[3];
public fixed ref readonly int F2[3];
}";
var comp = CreateCompilation(source, options: TestOptions.UnsafeReleaseDll, targetFramework: TargetFramework.Net70);
comp.VerifyEmitDiagnostics(
// (3,26): error CS9049: A fixed field must not be a ref field.
// public fixed ref int F1[3];
Diagnostic(ErrorCode.ERR_FixedFieldMustNotBeRef, "F1").WithLocation(3, 26),
// (4,35): error CS9049: A fixed field must not be a ref field.
// public fixed ref readonly int F2[3];
Diagnostic(ErrorCode.ERR_FixedFieldMustNotBeRef, "F2").WithLocation(4, 35));
}
[Fact]
public void FixedField_02()
{
var sourceA =
@".class public sealed S extends [mscorlib]System.ValueType
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.IsByRefLikeAttribute::.ctor() = (01 00 00 00)
.class sequential nested public sealed FixedBuffer extends [mscorlib]System.ValueType
{
.pack 0
.size 12
.field public int32 FixedElementField
}
.field public valuetype S/FixedBuffer& F
.custom instance void [mscorlib]System.Runtime.CompilerServices.FixedBufferAttribute::.ctor(class [mscorlib]System.Type, int32) = { type([mscorlib]System.Int32) int32(3) }
}";
var refA = CompileIL(sourceA);
var sourceB =
@"using System;
class Program
{
unsafe static void Main()
{
var s = new S();
Console.WriteLine(s.F[1]);
}
}";
var comp = CreateCompilation(sourceB, references: new[] { refA }, options: TestOptions.UnsafeReleaseExe, targetFramework: TargetFramework.Net70);
comp.VerifyEmitDiagnostics(
// (7,29): error CS0570: 'S.F' is not supported by the language
// Console.WriteLine(s.F[1]);
Diagnostic(ErrorCode.ERR_BindToBogus, "F").WithArguments("S.F").WithLocation(7, 29));
}
[Fact]
public void Volatile()
{
var sourceA =
@".class public sealed R extends [mscorlib]System.ValueType
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.IsByRefLikeAttribute::.ctor() = (01 00 00 00)
.field public int32& modreq([mscorlib]System.Runtime.CompilerServices.IsVolatile) F1
.field public int32 modreq([mscorlib]System.Runtime.CompilerServices.IsVolatile)& F2
}";
var refA = CompileIL(sourceA);
var sourceB =
@"using System;
class Program
{
static void Main()
{
var r = new R();
Console.WriteLine(r.F1);
Console.WriteLine(r.F2);
}
}";
var comp = CreateCompilation(sourceB, references: new[] { refA }, targetFramework: TargetFramework.Net70);
comp.VerifyEmitDiagnostics(
// (7,29): error CS0570: 'R.F1' is not supported by the language
// Console.WriteLine(r.F1);
Diagnostic(ErrorCode.ERR_BindToBogus, "F1").WithArguments("R.F1").WithLocation(7, 29),
// (8,29): error CS0570: 'R.F2' is not supported by the language
// Console.WriteLine(r.F2);
Diagnostic(ErrorCode.ERR_BindToBogus, "F2").WithArguments("R.F2").WithLocation(8, 29));
}
[Fact]
public void Modifiers()
{
var source =
@"#pragma warning disable 0169
ref struct R
{
static ref int _s1;
static ref readonly int _s2;
const ref int _c1 = default;
const ref readonly int _c2 = default;
volatile ref int _v1;
volatile ref readonly int _v2;
}";
var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70);
comp.VerifyEmitDiagnostics(
// (4,20): error CS0106: The modifier 'static' is not valid for this item
// static ref int _s1;
Diagnostic(ErrorCode.ERR_BadMemberFlag, "_s1").WithArguments("static").WithLocation(4, 20),
// (5,29): error CS0106: The modifier 'static' is not valid for this item
// static ref readonly int _s2;
Diagnostic(ErrorCode.ERR_BadMemberFlag, "_s2").WithArguments("static").WithLocation(5, 29),
// (6,19): error CS0106: The modifier 'static' is not valid for this item
// const ref int _c1 = default;
Diagnostic(ErrorCode.ERR_BadMemberFlag, "_c1").WithArguments("static").WithLocation(6, 19),
// (6,19): error CS0106: The modifier 'const' is not valid for this item
// const ref int _c1 = default;
Diagnostic(ErrorCode.ERR_BadMemberFlag, "_c1").WithArguments("const").WithLocation(6, 19),
// (6,23): error CS8172: Cannot initialize a by-reference variable with a value
// const ref int _c1 = default;
Diagnostic(ErrorCode.ERR_InitializeByReferenceVariableWithValue, "= default").WithLocation(6, 23),
// (6,25): error CS1510: A ref or out value must be an assignable variable
// const ref int _c1 = default;
Diagnostic(ErrorCode.ERR_RefLvalueExpected, "default").WithLocation(6, 25),
// (7,28): error CS0106: The modifier 'static' is not valid for this item
// const ref readonly int _c2 = default;
Diagnostic(ErrorCode.ERR_BadMemberFlag, "_c2").WithArguments("static").WithLocation(7, 28),
// (7,28): error CS0106: The modifier 'const' is not valid for this item
// const ref readonly int _c2 = default;
Diagnostic(ErrorCode.ERR_BadMemberFlag, "_c2").WithArguments("const").WithLocation(7, 28),
// (7,32): error CS8172: Cannot initialize a by-reference variable with a value
// const ref readonly int _c2 = default;
Diagnostic(ErrorCode.ERR_InitializeByReferenceVariableWithValue, "= default").WithLocation(7, 32),
// (7,34): error CS8156: An expression cannot be used in this context because it may not be passed or returned by reference
// const ref readonly int _c2 = default;
Diagnostic(ErrorCode.ERR_RefReturnLvalueExpected, "default").WithLocation(7, 34),
// (8,22): error CS0106: The modifier 'volatile' is not valid for this item
// volatile ref int _v1;
Diagnostic(ErrorCode.ERR_BadMemberFlag, "_v1").WithArguments("volatile").WithLocation(8, 22),
// (9,31): error CS0106: The modifier 'volatile' is not valid for this item
// volatile ref readonly int _v2;
Diagnostic(ErrorCode.ERR_BadMemberFlag, "_v2").WithArguments("volatile").WithLocation(9, 31));
}
[Fact]
public void UnsafeContext_PointerType_MethodParameter()
{
var source = @"
public ref struct S
{
public int F1;
}
public ref struct S2
{
public ref int F1;
}
class C
{
void M(
S* s, // 1
S2* s2, // 2, 3
C* c) // 4, 5
{
}
unsafe void M2(
S* s,
S2* s2, // 6
C* c) // 7
{
}
}
";
var comp = CreateCompilation(source, options: TestOptions.UnsafeReleaseDll, targetFramework: TargetFramework.Net70);
comp.VerifyEmitDiagnostics(
// (14,9): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context
// S* s, // 1
Diagnostic(ErrorCode.ERR_UnsafeNeeded, "S*").WithLocation(14, 9),
// (15,9): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context
// S2* s2, // 2, 3
Diagnostic(ErrorCode.ERR_UnsafeNeeded, "S2*").WithLocation(15, 9),
// (15,13): warning CS8500: This takes the address of, gets the size of, or declares a pointer to a managed type ('S2')
// S2* s2, // 2, 3
Diagnostic(ErrorCode.WRN_ManagedAddr, "s2").WithArguments("S2").WithLocation(15, 13),
// (16,9): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context
// C* c) // 4, 5
Diagnostic(ErrorCode.ERR_UnsafeNeeded, "C*").WithLocation(16, 9),
// (16,12): warning CS8500: This takes the address of, gets the size of, or declares a pointer to a managed type ('C')
// C* c) // 4, 5
Diagnostic(ErrorCode.WRN_ManagedAddr, "c").WithArguments("C").WithLocation(16, 12),
// (22,13): warning CS8500: This takes the address of, gets the size of, or declares a pointer to a managed type ('S2')
// S2* s2, // 6
Diagnostic(ErrorCode.WRN_ManagedAddr, "s2").WithArguments("S2").WithLocation(22, 13),
// (23,12): warning CS8500: This takes the address of, gets the size of, or declares a pointer to a managed type ('C')
// C* c) // 7
Diagnostic(ErrorCode.WRN_ManagedAddr, "c").WithArguments("C").WithLocation(23, 12)
);
}
[Fact]
public void UnsafeContext_PointerType_MethodReturnType()
{
var source = @"
public ref struct S
{
public int F1;
}
public ref struct S2
{
public ref int F1;
}
unsafe class C
{
S* M1() => (S*)null;
S2* M2() => (S2*)null; // 1
C* M3() => (C*)null; // 2
}
";
var comp = CreateCompilation(source, options: TestOptions.UnsafeReleaseDll, targetFramework: TargetFramework.Net70);
comp.VerifyEmitDiagnostics(
// (14,9): warning CS8500: This takes the address of, gets the size of, or declares a pointer to a managed type ('S2')
// S2* M2() => (S2*)null; // 1
Diagnostic(ErrorCode.WRN_ManagedAddr, "M2").WithArguments("S2").WithLocation(14, 9),
// (14,18): warning CS8500: This takes the address of, gets the size of, or declares a pointer to a managed type ('S2')
// S2* M2() => (S2*)null; // 1
Diagnostic(ErrorCode.WRN_ManagedAddr, "S2*").WithArguments("S2").WithLocation(14, 18),
// (15,8): warning CS8500: This takes the address of, gets the size of, or declares a pointer to a managed type ('C')
// C* M3() => (C*)null; // 2
Diagnostic(ErrorCode.WRN_ManagedAddr, "M3").WithArguments("C").WithLocation(15, 8),
// (15,17): warning CS8500: This takes the address of, gets the size of, or declares a pointer to a managed type ('C')
// C* M3() => (C*)null; // 2
Diagnostic(ErrorCode.WRN_ManagedAddr, "C*").WithArguments("C").WithLocation(15, 17)
);
}
[Fact]
public void UnsafeContext_PointerType_LocalDeclaration()
{
var source = @"
public ref struct S
{
public int F1;
}
public ref struct S2
{
public ref int F1;
}
class C
{
unsafe S M2()
{
S* s = null;
return *s;
}
unsafe S2 M3()
{
S2* s2 = null; // 1
return *s2;
}
unsafe C M4()
{
C* c = null; // 2
return *c;
}
}
";
var comp = CreateCompilation(source, options: TestOptions.UnsafeReleaseDll, targetFramework: TargetFramework.Net70);
comp.VerifyEmitDiagnostics(
// (20,9): warning CS8500: This takes the address of, gets the size of, or declares a pointer to a managed type ('S2')
// S2* s2 = null; // 1
Diagnostic(ErrorCode.WRN_ManagedAddr, "S2*").WithArguments("S2").WithLocation(20, 9),
// (25,9): warning CS8500: This takes the address of, gets the size of, or declares a pointer to a managed type ('C')
// C* c = null; // 2
Diagnostic(ErrorCode.WRN_ManagedAddr, "C*").WithArguments("C").WithLocation(25, 9)
);
var verifier = CompileAndVerify(comp, verify: Verification.Skipped);
verifier.VerifyIL("C.M3", @"
{
// Code size 10 (0xa)
.maxstack 1
.locals init (S2* V_0) //s2
IL_0000: ldc.i4.0
IL_0001: conv.u
IL_0002: stloc.0
IL_0003: ldloc.0
IL_0004: ldobj ""S2""
IL_0009: ret
}
");
verifier.VerifyIL("C.M4", @"
{
// Code size 6 (0x6)
.maxstack 1
.locals init (C* V_0) //c
IL_0000: ldc.i4.0
IL_0001: conv.u
IL_0002: stloc.0
IL_0003: ldloc.0
IL_0004: ldind.ref
IL_0005: ret
}
");
}
[Fact]
public void UnsafeContext_PointerType_FixedStatement()
{
var source = @"
public ref struct S
{
public int F1;
}
public ref struct S2
{
public ref int F1;
}
class C
{
ref S Prop { get => throw null; }
ref S2 Prop2 { get => throw null; }
ref C Prop3 { get => throw null; }
unsafe void M()
{
fixed (S* x1 = &Prop) { }
}
unsafe void M2()
{
fixed (S2* x2 = &Prop2) { } // 1
}
unsafe void M3()
{
fixed (void* y2 = &Prop2) { } // 2
}
unsafe void M4()
{
fixed (C* x3 = &Prop3) { } // 3
}
unsafe void M5()
{
fixed (void* y3 = &Prop3) { } // 4
}
}
";
// SPEC:
// A fixed_pointer_initializer can be one of the following:
// The token “&” followed by a variable_reference to a moveable variable of type T,
// provided the type T* is implicitly convertible to the pointer type given in the fixed statement.
var comp = CreateCompilation(source, options: TestOptions.UnsafeReleaseDll, targetFramework: TargetFramework.Net70);
comp.VerifyEmitDiagnostics(
// (23,16): warning CS8500: This takes the address of, gets the size of, or declares a pointer to a managed type ('S2')
// fixed (S2* x2 = &Prop2) { } // 1
Diagnostic(ErrorCode.WRN_ManagedAddr, "S2*").WithArguments("S2").WithLocation(23, 16),
// (23,25): warning CS8500: This takes the address of, gets the size of, or declares a pointer to a managed type ('S2')
// fixed (S2* x2 = &Prop2) { } // 1
Diagnostic(ErrorCode.WRN_ManagedAddr, "&Prop2").WithArguments("S2").WithLocation(23, 25),
// (23,25): warning CS8500: This takes the address of, gets the size of, or declares a pointer to a managed type ('S2')
// fixed (S2* x2 = &Prop2) { } // 1
Diagnostic(ErrorCode.WRN_ManagedAddr, "&Prop2").WithArguments("S2").WithLocation(23, 25),
// (27,27): warning CS8500: This takes the address of, gets the size of, or declares a pointer to a managed type ('S2')
// fixed (void* y2 = &Prop2) { } // 2
Diagnostic(ErrorCode.WRN_ManagedAddr, "&Prop2").WithArguments("S2").WithLocation(27, 27),
// (27,27): warning CS8500: This takes the address of, gets the size of, or declares a pointer to a managed type ('S2')
// fixed (void* y2 = &Prop2) { } // 2
Diagnostic(ErrorCode.WRN_ManagedAddr, "&Prop2").WithArguments("S2").WithLocation(27, 27),
// (31,16): warning CS8500: This takes the address of, gets the size of, or declares a pointer to a managed type ('C')
// fixed (C* x3 = &Prop3) { } // 3
Diagnostic(ErrorCode.WRN_ManagedAddr, "C*").WithArguments("C").WithLocation(31, 16),
// (31,24): warning CS8500: This takes the address of, gets the size of, or declares a pointer to a managed type ('C')
// fixed (C* x3 = &Prop3) { } // 3
Diagnostic(ErrorCode.WRN_ManagedAddr, "&Prop3").WithArguments("C").WithLocation(31, 24),
// (31,24): warning CS8500: This takes the address of, gets the size of, or declares a pointer to a managed type ('C')
// fixed (C* x3 = &Prop3) { } // 3
Diagnostic(ErrorCode.WRN_ManagedAddr, "&Prop3").WithArguments("C").WithLocation(31, 24),
// (35,27): warning CS8500: This takes the address of, gets the size of, or declares a pointer to a managed type ('C')
// fixed (void* y3 = &Prop3) { } // 4
Diagnostic(ErrorCode.WRN_ManagedAddr, "&Prop3").WithArguments("C").WithLocation(35, 27),
// (35,27): warning CS8500: This takes the address of, gets the size of, or declares a pointer to a managed type ('C')
// fixed (void* y3 = &Prop3) { } // 4
Diagnostic(ErrorCode.WRN_ManagedAddr, "&Prop3").WithArguments("C").WithLocation(35, 27)
);
var verifier = CompileAndVerify(comp, verify: Verification.Skipped);
verifier.VerifyIL("C.M2", @"
{
// Code size 13 (0xd)
.maxstack 1
.locals init (pinned S2& V_0)
IL_0000: ldarg.0
IL_0001: call ""ref S2 C.Prop2.get""
IL_0006: stloc.0
IL_0007: ldloc.0
IL_0008: pop
IL_0009: ldc.i4.0
IL_000a: conv.u
IL_000b: stloc.0
IL_000c: ret
}
");
verifier.VerifyIL("C.M4", @"
{
// Code size 13 (0xd)
.maxstack 1
.locals init (pinned C& V_0)
IL_0000: ldarg.0
IL_0001: call ""ref C C.Prop3.get""
IL_0006: stloc.0
IL_0007: ldloc.0
IL_0008: pop
IL_0009: ldc.i4.0
IL_000a: conv.u
IL_000b: stloc.0
IL_000c: ret
}
");
}
[Fact]
public void UnsafeContext_PointerType_Cast()
{
var source = @"
public ref struct S
{
public int F1;
}
public ref struct S2
{
public ref int F1;
}
class C
{
void M(void* p)
{
_ = (S*)p; // 1
_ = (S2*)p; // 2
_ = (C*)p; // 3
}
unsafe void M2(void* p)
{
_ = (S*)p;
_ = (S2*)p; // 4
_ = (C*)p; // 5
}
}
";
var comp = CreateCompilation(source, options: TestOptions.UnsafeReleaseDll, targetFramework: TargetFramework.Net70);
comp.VerifyEmitDiagnostics(
// (13,12): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context
// void M(void* p)
Diagnostic(ErrorCode.ERR_UnsafeNeeded, "void*").WithLocation(13, 12),
// (15,9): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context
// _ = (S*)p; // 1
Diagnostic(ErrorCode.ERR_UnsafeNeeded, "_ = (S*)p").WithLocation(15, 9),
// (15,13): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context
// _ = (S*)p; // 1
Diagnostic(ErrorCode.ERR_UnsafeNeeded, "(S*)p").WithLocation(15, 13),
// (15,14): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context
// _ = (S*)p; // 1
Diagnostic(ErrorCode.ERR_UnsafeNeeded, "S*").WithLocation(15, 14),
// (15,17): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context
// _ = (S*)p; // 1
Diagnostic(ErrorCode.ERR_UnsafeNeeded, "p").WithLocation(15, 17),
// (16,9): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context
// _ = (S2*)p; // 2
Diagnostic(ErrorCode.ERR_UnsafeNeeded, "_ = (S2*)p").WithLocation(16, 9),
// (16,13): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context
// _ = (S2*)p; // 2
Diagnostic(ErrorCode.ERR_UnsafeNeeded, "(S2*)p").WithLocation(16, 13),
// (16,14): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context
// _ = (S2*)p; // 2
Diagnostic(ErrorCode.ERR_UnsafeNeeded, "S2*").WithLocation(16, 14),
// (16,14): warning CS8500: This takes the address of, gets the size of, or declares a pointer to a managed type ('S2')
// _ = (S2*)p; // 2
Diagnostic(ErrorCode.WRN_ManagedAddr, "S2*").WithArguments("S2").WithLocation(16, 14),
// (16,18): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context
// _ = (S2*)p; // 2
Diagnostic(ErrorCode.ERR_UnsafeNeeded, "p").WithLocation(16, 18),
// (17,9): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context
// _ = (C*)p; // 3
Diagnostic(ErrorCode.ERR_UnsafeNeeded, "_ = (C*)p").WithLocation(17, 9),
// (17,13): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context
// _ = (C*)p; // 3
Diagnostic(ErrorCode.ERR_UnsafeNeeded, "(C*)p").WithLocation(17, 13),
// (17,14): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context
// _ = (C*)p; // 3
Diagnostic(ErrorCode.ERR_UnsafeNeeded, "C*").WithLocation(17, 14),
// (17,14): warning CS8500: This takes the address of, gets the size of, or declares a pointer to a managed type ('C')
// _ = (C*)p; // 3
Diagnostic(ErrorCode.WRN_ManagedAddr, "C*").WithArguments("C").WithLocation(17, 14),
// (17,17): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context
// _ = (C*)p; // 3
Diagnostic(ErrorCode.ERR_UnsafeNeeded, "p").WithLocation(17, 17),
// (23,14): warning CS8500: This takes the address of, gets the size of, or declares a pointer to a managed type ('S2')
// _ = (S2*)p; // 4
Diagnostic(ErrorCode.WRN_ManagedAddr, "S2*").WithArguments("S2").WithLocation(23, 14),
// (24,14): warning CS8500: This takes the address of, gets the size of, or declares a pointer to a managed type ('C')
// _ = (C*)p; // 5
Diagnostic(ErrorCode.WRN_ManagedAddr, "C*").WithArguments("C").WithLocation(24, 14)
);
}
[Fact]
public void UnsafeContext_SizeOf()
{
var source = @"
public ref struct S
{
public int F1;
}
public ref struct S2
{
public ref int F1;
}
class C
{
unsafe int M1()
{
return sizeof(S*);
}
unsafe int M2()
{
return sizeof(S2*); // 1
}
unsafe int M3()
{
return sizeof(C*); // 2
}
unsafe int M4()
{
return sizeof(S2); // 3
}
unsafe int M5()
{
return sizeof(C); // 4
}
}
";
var comp = CreateCompilation(source, options: TestOptions.UnsafeReleaseDll, targetFramework: TargetFramework.Net70);
comp.VerifyEmitDiagnostics(
// (19,23): warning CS8500: This takes the address of, gets the size of, or declares a pointer to a managed type ('S2')
// return sizeof(S2*); // 1
Diagnostic(ErrorCode.WRN_ManagedAddr, "S2*").WithArguments("S2").WithLocation(19, 23),
// (23,23): warning CS8500: This takes the address of, gets the size of, or declares a pointer to a managed type ('C')
// return sizeof(C*); // 2
Diagnostic(ErrorCode.WRN_ManagedAddr, "C*").WithArguments("C").WithLocation(23, 23),
// (27,16): warning CS8500: This takes the address of, gets the size of, or declares a pointer to a managed type ('S2')
// return sizeof(S2); // 3
Diagnostic(ErrorCode.WRN_ManagedAddr, "sizeof(S2)").WithArguments("S2").WithLocation(27, 16),
// (31,16): warning CS8500: This takes the address of, gets the size of, or declares a pointer to a managed type ('C')
// return sizeof(C); // 4
Diagnostic(ErrorCode.WRN_ManagedAddr, "sizeof(C)").WithArguments("C").WithLocation(31, 16)
);
var verifier = CompileAndVerify(comp, verify: Verification.Skipped);
verifier.VerifyIL("C.M2", @"
{
// Code size 7 (0x7)
.maxstack 1
IL_0000: sizeof ""S2*""
IL_0006: ret
}
");
verifier.VerifyIL("C.M4", @"
{
// Code size 7 (0x7)
.maxstack 1
IL_0000: sizeof ""S2""
IL_0006: ret
}
");
}
[Fact]
public void UnsafeContext_TypeOf()
{
var source = @"
public ref struct S
{
public int F1;
}
public ref struct S2
{
public ref int F1;
}
class C
{
unsafe object M()
{
return typeof(S*);
}
unsafe object M2()
{
return typeof(S2*); // 1
}
unsafe object M3()
{
return typeof(C*); // 2
}
}
";
var comp = CreateCompilation(source, options: TestOptions.UnsafeReleaseDll, targetFramework: TargetFramework.Net70);
comp.VerifyEmitDiagnostics(
// (19,23): warning CS8500: This takes the address of, gets the size of, or declares a pointer to a managed type ('S2')
// return typeof(S2*); // 1
Diagnostic(ErrorCode.WRN_ManagedAddr, "S2*").WithArguments("S2").WithLocation(19, 23),
// (23,23): warning CS8500: This takes the address of, gets the size of, or declares a pointer to a managed type ('C')
// return typeof(C*); // 2
Diagnostic(ErrorCode.WRN_ManagedAddr, "C*").WithArguments("C").WithLocation(23, 23)
);
var verifier = CompileAndVerify(comp, verify: Verification.Skipped);
verifier.VerifyIL("C.M2", @"
{
// Code size 11 (0xb)
.maxstack 1
IL_0000: ldtoken ""S2*""
IL_0005: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)""
IL_000a: ret
}
");
verifier.VerifyIL("C.M3", @"
{
// Code size 11 (0xb)
.maxstack 1
IL_0000: ldtoken ""C*""
IL_0005: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)""
IL_000a: ret
}
");
}
[Fact]
public void UnsafeContext_AddressOf()
{
var source = @"
ref struct S
{
int F1;
}
ref struct S2
{
ref int F1;
}
class C
{
void M(S s)
{
var x = &s; // 1
}
void M2(S2 s)
{
var x = &s; // 2
}
void M3(ref S2 s)
{
var x = &s; // 3
}
}
unsafe class C2
{
void M(S s)
{
var x = &s;
}
void M2(S2 s)
{
var x = &s; // 4
}
void M3(ref S2 s)
{
var x = &s; // 5
}
}
";
var comp = CreateCompilation(source, options: TestOptions.UnsafeReleaseDll, targetFramework: TargetFramework.Net70);
comp.VerifyEmitDiagnostics(
// (15,17): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context
// var x = &s; // 1
Diagnostic(ErrorCode.ERR_UnsafeNeeded, "&s").WithLocation(15, 17),
// (19,17): warning CS8500: This takes the address of, gets the size of, or declares a pointer to a managed type ('S2')
// var x = &s; // 2
Diagnostic(ErrorCode.WRN_ManagedAddr, "&s").WithArguments("S2").WithLocation(19, 17),
// (19,17): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context
// var x = &s; // 2
Diagnostic(ErrorCode.ERR_UnsafeNeeded, "&s").WithLocation(19, 17),
// (23,17): warning CS8500: This takes the address of, gets the size of, or declares a pointer to a managed type ('S2')
// var x = &s; // 3
Diagnostic(ErrorCode.WRN_ManagedAddr, "&s").WithArguments("S2").WithLocation(23, 17),
// (23,17): error CS0212: You can only take the address of an unfixed expression inside of a fixed statement initializer
// var x = &s; // 3
Diagnostic(ErrorCode.ERR_FixedNeeded, "&s").WithLocation(23, 17),
// (35,17): warning CS8500: This takes the address of, gets the size of, or declares a pointer to a managed type ('S2')
// var x = &s; // 4
Diagnostic(ErrorCode.WRN_ManagedAddr, "&s").WithArguments("S2").WithLocation(35, 17),
// (39,17): warning CS8500: This takes the address of, gets the size of, or declares a pointer to a managed type ('S2')
// var x = &s; // 5
Diagnostic(ErrorCode.WRN_ManagedAddr, "&s").WithArguments("S2").WithLocation(39, 17),
// (39,17): error CS0212: You can only take the address of an unfixed expression inside of a fixed statement initializer
// var x = &s; // 5
Diagnostic(ErrorCode.ERR_FixedNeeded, "&s").WithLocation(39, 17)
);
source = @"
ref struct S2
{
ref int F1;
}
unsafe class C2
{
void* M2(S2 s)
{
var x = &s; // 1
return x;
}
}
";
comp = CreateCompilation(source, options: TestOptions.UnsafeReleaseDll, targetFramework: TargetFramework.Net70);
comp.VerifyEmitDiagnostics(
// (11,17): warning CS8500: This takes the address of, gets the size of, or declares a pointer to a managed type ('S2')
// var x = &s; // 1
Diagnostic(ErrorCode.WRN_ManagedAddr, "&s").WithArguments("S2").WithLocation(11, 17)
);
var verifier = CompileAndVerify(comp, verify: Verification.Skipped);
verifier.VerifyIL("C2.M2", @"
{
// Code size 4 (0x4)
.maxstack 1
IL_0000: ldarga.s V_1
IL_0002: conv.u
IL_0003: ret
}
");
}
[Fact]
public void UnsafeContext_AddressOf_CastToIntPtrPointer()
{
var source = @"
using System;
ref struct S2
{
ref int F1;
}
unsafe class C2
{
IntPtr* M2(S2 s)
{
return (IntPtr*)&s; // 1
}
}
";
var comp = CreateCompilation(source, options: TestOptions.UnsafeReleaseDll, targetFramework: TargetFramework.Net70);
comp.VerifyEmitDiagnostics(
// (13,25): warning CS8500: This takes the address of, gets the size of, or declares a pointer to a managed type ('S2')
// return (IntPtr*)&s; // 1
Diagnostic(ErrorCode.WRN_ManagedAddr, "&s").WithArguments("S2").WithLocation(13, 25)
);
var verifier = CompileAndVerify(comp, verify: Verification.Skipped);
verifier.VerifyIL("C2.M2", @"
{
// Code size 4 (0x4)
.maxstack 1
IL_0000: ldarga.s V_1
IL_0002: conv.u
IL_0003: ret
}
");
}
[Fact]
public void UnsafeContext_Assignment()
{
var source = @"
using System;
public ref struct S2
{
public ref int F1;
unsafe static void Assign(IntPtr* p, ref S2 r)
{
*(S2*)p = r;
}
}
";
var comp = CreateCompilation(source, options: TestOptions.UnsafeReleaseDll, targetFramework: TargetFramework.Net70);
comp.VerifyEmitDiagnostics(
// (10,11): warning CS8500: This takes the address of, gets the size of, or declares a pointer to a managed type ('S2')
// *(S2*)p = r;
Diagnostic(ErrorCode.WRN_ManagedAddr, "S2*").WithArguments("S2").WithLocation(10, 11)
);
var verifier = CompileAndVerify(comp, verify: Verification.Skipped);
verifier.VerifyIL("S2.Assign", @"
{
// Code size 13 (0xd)
.maxstack 2
IL_0000: ldarg.0
IL_0001: ldarg.1
IL_0002: ldobj ""S2""
IL_0007: stobj ""S2""
IL_000c: ret
}
");
}
[Fact]
public void UnsafeContext_PointerMemberAccess()
{
var source = @"
public ref struct S
{
public int F1;
}
public ref struct S2
{
public ref int F1;
}
unsafe class C
{
void M(S s)
{
_ = (&s)->F1; // 1
}
int M2(S2 s)
{
return (&s)->F1; // 2
}
}
";
var comp = CreateCompilation(source, options: TestOptions.UnsafeReleaseDll, targetFramework: TargetFramework.Net70);
comp.VerifyEmitDiagnostics(
// (19,17): warning CS8500: This takes the address of, gets the size of, or declares a pointer to a managed type ('S2')
// return (&s)->F1; // 2
Diagnostic(ErrorCode.WRN_ManagedAddr, "&s").WithArguments("S2").WithLocation(19, 17)
);
var verifier = CompileAndVerify(comp, verify: Verification.Skipped);
verifier.VerifyIL("C.M2", @"
{
// Code size 10 (0xa)
.maxstack 1
IL_0000: ldarga.s V_1
IL_0002: conv.u
IL_0003: ldfld ""ref int S2.F1""
IL_0008: ldind.i4
IL_0009: ret
}
");
}
[Fact]
public void UnsafeContext_PointerElementAccess()
{
var source = @"
public ref struct S
{
public int F1;
}
public ref struct S2
{
public ref int F1;
}
unsafe class C
{
S M(S s)
{
return (&s)[0];
}
S2 M2(S2 s)
{
return (&s)[0]; // 1
}
}
";
var comp = CreateCompilation(source, options: TestOptions.UnsafeReleaseDll, targetFramework: TargetFramework.Net70);
comp.VerifyEmitDiagnostics(
// (19,17): warning CS8500: This takes the address of, gets the size of, or declares a pointer to a managed type ('S2')
// return (&s)[0]; // 1
Diagnostic(ErrorCode.WRN_ManagedAddr, "&s").WithArguments("S2").WithLocation(19, 17)
);
var verifier = CompileAndVerify(comp, verify: Verification.Skipped);
verifier.VerifyIL("C.M2", @"
{
// Code size 9 (0x9)
.maxstack 1
IL_0000: ldarga.s V_1
IL_0002: conv.u
IL_0003: ldobj ""S2""
IL_0008: ret
}
");
}
[Fact]
public void UnsafeContext_Stackalloc()
{
var source = @"
public ref struct S
{
public int F1;
}
public ref struct S2
{
public ref int F1;
}
class C
{
unsafe void M()
{
var x1 = stackalloc S[0];
var x2 = stackalloc S2[0]; // 1
var x3 = stackalloc C[0]; // 2
S* y1 = stackalloc S[0];
S2* y2 = stackalloc S2[0]; // 3
C* y3 = stackalloc C[0]; // 4
}
}
";
var spanReference = CreateCompilation(SpanSource, options: TestOptions.UnsafeReleaseDll);
var comp = CreateCompilation(source, references: new[] { spanReference.EmitToImageReference() }, options: TestOptions.UnsafeReleaseDll, targetFramework: TargetFramework.Net70);
comp.VerifyEmitDiagnostics(
// (16,29): error CS0208: Cannot take the address of, get the size of, or declare a pointer to a managed type ('S2')
// var x2 = stackalloc S2[0]; // 1
Diagnostic(ErrorCode.ERR_ManagedAddr, "S2").WithArguments("S2").WithLocation(16, 29),
// (17,29): error CS0208: Cannot take the address of, get the size of, or declare a pointer to a managed type ('C')
// var x3 = stackalloc C[0]; // 2
Diagnostic(ErrorCode.ERR_ManagedAddr, "C").WithArguments("C").WithLocation(17, 29),
// (20,9): warning CS8500: This takes the address of, gets the size of, or declares a pointer to a managed type ('S2')
// S2* y2 = stackalloc S2[0]; // 3
Diagnostic(ErrorCode.WRN_ManagedAddr, "S2*").WithArguments("S2").WithLocation(20, 9),
// (20,29): error CS0208: Cannot take the address of, get the size of, or declare a pointer to a managed type ('S2')
// S2* y2 = stackalloc S2[0]; // 3
Diagnostic(ErrorCode.ERR_ManagedAddr, "S2").WithArguments("S2").WithLocation(20, 29),
// (21,9): warning CS8500: This takes the address of, gets the size of, or declares a pointer to a managed type ('C')
// C* y3 = stackalloc C[0]; // 4
Diagnostic(ErrorCode.WRN_ManagedAddr, "C*").WithArguments("C").WithLocation(21, 9),
// (21,28): error CS0208: Cannot take the address of, get the size of, or declare a pointer to a managed type ('C')
// C* y3 = stackalloc C[0]; // 4
Diagnostic(ErrorCode.ERR_ManagedAddr, "C").WithArguments("C").WithLocation(21, 28)
);
}
[Fact]
public void UnsafeContext_Stackalloc_ImplicitType()
{
var source = @"
public ref struct S
{
public int F1;
}
public ref struct S2
{
public ref int F1;
}
class C
{
unsafe void M()
{
var x1 = stackalloc[] { new S() };
var x2 = stackalloc[] { new S2() }; // 1
var x3 = stackalloc[] { new C() }; // 2
S* y1 = stackalloc[] { new S() };
S2* y2 = stackalloc[] { new S2() }; // 3
}
unsafe C M2()
{
C* y3 = stackalloc[] { new C() }; // 4
return y3[0];
}
}
";
var spanReference = CreateCompilation(SpanSource, options: TestOptions.UnsafeReleaseDll);
var comp = CreateCompilation(source, references: new[] { spanReference.EmitToImageReference() }, options: TestOptions.UnsafeReleaseDll, targetFramework: TargetFramework.Net70);
comp.VerifyEmitDiagnostics(
// (16,18): error CS0208: Cannot take the address of, get the size of, or declare a pointer to a managed type ('S2')
// var x2 = stackalloc[] { new S2() }; // 1
Diagnostic(ErrorCode.ERR_ManagedAddr, "stackalloc[] { new S2() }").WithArguments("S2").WithLocation(16, 18),
// (17,18): error CS0208: Cannot take the address of, get the size of, or declare a pointer to a managed type ('C')
// var x3 = stackalloc[] { new C() }; // 2
Diagnostic(ErrorCode.ERR_ManagedAddr, "stackalloc[] { new C() }").WithArguments("C").WithLocation(17, 18),
// (20,9): warning CS8500: This takes the address of, gets the size of, or declares a pointer to a managed type ('S2')
// S2* y2 = stackalloc[] { new S2() }; // 3
Diagnostic(ErrorCode.WRN_ManagedAddr, "S2*").WithArguments("S2").WithLocation(20, 9),
// (20,18): error CS0208: Cannot take the address of, get the size of, or declare a pointer to a managed type ('S2')
// S2* y2 = stackalloc[] { new S2() }; // 3
Diagnostic(ErrorCode.ERR_ManagedAddr, "stackalloc[] { new S2() }").WithArguments("S2").WithLocation(20, 18),
// (24,9): warning CS8500: This takes the address of, gets the size of, or declares a pointer to a managed type ('C')
// C* y3 = stackalloc[] { new C() }; // 4
Diagnostic(ErrorCode.WRN_ManagedAddr, "C*").WithArguments("C").WithLocation(24, 9),
// (24,17): error CS0208: Cannot take the address of, get the size of, or declare a pointer to a managed type ('C')
// C* y3 = stackalloc[] { new C() }; // 4
Diagnostic(ErrorCode.ERR_ManagedAddr, "stackalloc[] { new C() }").WithArguments("C").WithLocation(24, 17)
);
}
[Fact]
public void UnsafeContext_Stackalloc_PointerElementType()
{
var source = @"
public ref struct S
{
public int F1;
}
public ref struct S2
{
public ref int F1;
}
class C
{
unsafe void M()
{
var x1 = stackalloc S*[0];
var x2 = stackalloc S2*[0]; // 1
var x3 = stackalloc C*[0]; // 2
S** y1 = stackalloc S*[0];
S2** y2 = stackalloc S2*[0]; // 3
C** y3 = stackalloc C*[0]; // 4
}
}
";
var spanReference = CreateCompilation(SpanSource, options: TestOptions.UnsafeReleaseDll);
var comp = CreateCompilation(source, references: new[] { spanReference.EmitToImageReference() }, options: TestOptions.UnsafeReleaseDll, targetFramework: TargetFramework.Net70);
comp.VerifyEmitDiagnostics(
// (16,29): warning CS8500: This takes the address of, gets the size of, or declares a pointer to a managed type ('S2')
// var x2 = stackalloc S2*[0]; // 1
Diagnostic(ErrorCode.WRN_ManagedAddr, "S2*").WithArguments("S2").WithLocation(16, 29),
// (17,29): warning CS8500: This takes the address of, gets the size of, or declares a pointer to a managed type ('C')
// var x3 = stackalloc C*[0]; // 2
Diagnostic(ErrorCode.WRN_ManagedAddr, "C*").WithArguments("C").WithLocation(17, 29),
// (20,9): warning CS8500: This takes the address of, gets the size of, or declares a pointer to a managed type ('S2')
// S2** y2 = stackalloc S2*[0]; // 3
Diagnostic(ErrorCode.WRN_ManagedAddr, "S2*").WithArguments("S2").WithLocation(20, 9),
// (20,30): warning CS8500: This takes the address of, gets the size of, or declares a pointer to a managed type ('S2')
// S2** y2 = stackalloc S2*[0]; // 3
Diagnostic(ErrorCode.WRN_ManagedAddr, "S2*").WithArguments("S2").WithLocation(20, 30),
// (21,9): warning CS8500: This takes the address of, gets the size of, or declares a pointer to a managed type ('C')
// C** y3 = stackalloc C*[0]; // 4
Diagnostic(ErrorCode.WRN_ManagedAddr, "C*").WithArguments("C").WithLocation(21, 9),
// (21,29): warning CS8500: This takes the address of, gets the size of, or declares a pointer to a managed type ('C')
// C** y3 = stackalloc C*[0]; // 4
Diagnostic(ErrorCode.WRN_ManagedAddr, "C*").WithArguments("C").WithLocation(21, 29)
);
}
[Fact]
public void UnsafeContext_Stackalloc_PointerElementType_ImplicitType()
{
var source = @"
public ref struct S
{
public int F1;
}
public ref struct S2
{
public ref int F1;
}
class C
{
unsafe void M()
{
var s1 = (S*)null;
var s2 = (S2*)null; // 1
var s3 = (C*)null; // 2
var x1 = stackalloc[] { s1 };
var x2 = stackalloc[] { s2 };
var x3 = stackalloc[] { s3 };
S** y1 = stackalloc[] { s1 };
S2** y2 = stackalloc[] { s2 }; // 3
C** y3 = stackalloc[] { s3 }; // 4
}
}
";
var spanReference = CreateCompilation(SpanSource, options: TestOptions.UnsafeReleaseDll);
var comp = CreateCompilation(source, references: new[] { spanReference.EmitToImageReference() }, options: TestOptions.UnsafeReleaseDll, targetFramework: TargetFramework.Net70);
comp.VerifyEmitDiagnostics(
// (16,19): warning CS8500: This takes the address of, gets the size of, or declares a pointer to a managed type ('S2')
// var s2 = (S2*)null; // 1
Diagnostic(ErrorCode.WRN_ManagedAddr, "S2*").WithArguments("S2").WithLocation(16, 19),
// (17,19): warning CS8500: This takes the address of, gets the size of, or declares a pointer to a managed type ('C')
// var s3 = (C*)null; // 2
Diagnostic(ErrorCode.WRN_ManagedAddr, "C*").WithArguments("C").WithLocation(17, 19),
// (24,9): warning CS8500: This takes the address of, gets the size of, or declares a pointer to a managed type ('S2')
// S2** y2 = stackalloc[] { s2 }; // 3
Diagnostic(ErrorCode.WRN_ManagedAddr, "S2*").WithArguments("S2").WithLocation(24, 9),
// (25,9): warning CS8500: This takes the address of, gets the size of, or declares a pointer to a managed type ('C')
// C** y3 = stackalloc[] { s3 }; // 4
Diagnostic(ErrorCode.WRN_ManagedAddr, "C*").WithArguments("C").WithLocation(25, 9)
);
}
[Fact, WorkItem(63018, "https://github.com/dotnet/roslyn/issues/63018")]
public void InitRefField_AutoDefault()
{
var source = """
using System;
var x = 42;
scoped var r = new R();
r.field = ref x;
ref struct R
{
public ref int field;
public R()
{
Console.WriteLine("explicit ctor");
}
}
""";
var comp = CreateCompilation(source, options: TestOptions.ReleaseExe, targetFramework: TargetFramework.Net70);
comp.VerifyDiagnostics();
var verifier = CompileAndVerify(comp, verify: Verification.Skipped, expectedOutput: IncludeExpectedOutput("explicit ctor"));
verifier.VerifyIL("R..ctor()", @"
{
// Code size 19 (0x13)
.maxstack 2
IL_0000: ldarg.0
IL_0001: ldc.i4.0
IL_0002: conv.u
IL_0003: stfld ""ref int R.field""
IL_0008: ldstr ""explicit ctor""
IL_000d: call ""void System.Console.WriteLine(string)""
IL_0012: ret
}");
}
[Fact, WorkItem(63018, "https://github.com/dotnet/roslyn/issues/63018")]
public void InitRefField_UnsafeNullRef()
{
var source = """
using System;
var x = 42;
scoped var r = new R();
r.field = ref x;
ref struct R
{
public ref int field;
public R()
{
field = ref System.Runtime.CompilerServices.Unsafe.NullRef<int>();
Console.WriteLine("explicit ctor");
}
}
""";
var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70, options: TestOptions.ReleaseExe);
comp.VerifyDiagnostics();
var verifier = CompileAndVerify(comp, verify: Verification.Skipped, expectedOutput: IncludeExpectedOutput("explicit ctor"));
verifier.VerifyIL("R..ctor()", @"
{
// Code size 22 (0x16)
.maxstack 2
IL_0000: ldarg.0
IL_0001: call ""ref int System.Runtime.CompilerServices.Unsafe.NullRef<int>()""
IL_0006: stfld ""ref int R.field""
IL_000b: ldstr ""explicit ctor""
IL_0010: call ""void System.Console.WriteLine(string)""
IL_0015: ret
}");
}
[Fact, WorkItem(63018, "https://github.com/dotnet/roslyn/issues/63018")]
public void InitRefField_AutoDefault_RefReadonly()
{
var source = """
using System;
var x = 42;
scoped var r = new R();
r.field = ref x;
ref struct R
{
public ref readonly int field;
public R()
{
Console.WriteLine("explicit ctor");
}
}
""";
var comp = CreateCompilation(source, options: TestOptions.ReleaseExe, targetFramework: TargetFramework.Net70);
comp.VerifyDiagnostics();
var verifier = CompileAndVerify(comp, verify: Verification.Skipped, expectedOutput: IncludeExpectedOutput("explicit ctor"));
verifier.VerifyIL("R..ctor()", @"
{
// Code size 19 (0x13)
.maxstack 2
IL_0000: ldarg.0
IL_0001: ldc.i4.0
IL_0002: conv.u
IL_0003: stfld ""ref readonly int R.field""
IL_0008: ldstr ""explicit ctor""
IL_000d: call ""void System.Console.WriteLine(string)""
IL_0012: ret
}");
}
[Fact, WorkItem(63018, "https://github.com/dotnet/roslyn/issues/63018")]
public void InitRefField_AutoDefault_ReadonlyRef()
{
var source = """
using System;
var r = new R();
ref struct R
{
public readonly ref int field;
public R()
{
Console.WriteLine("explicit ctor");
}
}
""";
var comp = CreateCompilation(source, options: TestOptions.ReleaseExe, targetFramework: TargetFramework.Net70);
comp.VerifyDiagnostics(
// (7,29): warning CS0649: Field 'R.field' is never assigned to, and will always have its default value 0
// public readonly ref int field;
Diagnostic(ErrorCode.WRN_UnassignedInternalField, "field").WithArguments("R.field", "0").WithLocation(7, 29)
);
var verifier = CompileAndVerify(comp, verify: Verification.Skipped, expectedOutput: IncludeExpectedOutput("explicit ctor"));
verifier.VerifyIL("R..ctor()", @"
{
// Code size 19 (0x13)
.maxstack 2
IL_0000: ldarg.0
IL_0001: ldc.i4.0
IL_0002: conv.u
IL_0003: stfld ""ref int R.field""
IL_0008: ldstr ""explicit ctor""
IL_000d: call ""void System.Console.WriteLine(string)""
IL_0012: ret
}");
}
[Fact, WorkItem(63018, "https://github.com/dotnet/roslyn/issues/63018")]
public void InitRefField_AutoDefault_WithOtherFieldInitializer()
{
var source = """
using System;
var x = 42;
scoped var r = new R();
r.field = ref x;
ref struct R
{
public ref int field;
public int otherField = 42;
public R()
{
Console.WriteLine("explicit ctor");
}
}
""";
var comp = CreateCompilation(source, parseOptions: TestOptions.Regular11, options: TestOptions.ReleaseExe, targetFramework: TargetFramework.Net70);
comp.VerifyDiagnostics();
var verifier = CompileAndVerify(comp, verify: Verification.Skipped, expectedOutput: IncludeExpectedOutput("explicit ctor"));
verifier.VerifyIL("R..ctor()", @"
{
// Code size 27 (0x1b)
.maxstack 2
IL_0000: ldarg.0
IL_0001: ldc.i4.0
IL_0002: conv.u
IL_0003: stfld ""ref int R.field""
IL_0008: ldarg.0
IL_0009: ldc.i4.s 42
IL_000b: stfld ""int R.otherField""
IL_0010: ldstr ""explicit ctor""
IL_0015: call ""void System.Console.WriteLine(string)""
IL_001a: ret
}");
}
/// <summary>
/// Unexpected modreq().
/// </summary>
[Fact]
public void RefCustomModifiers_UseSiteDiagnostic_02()
{
var sourceA =
@".class public sealed A extends [mscorlib]System.ValueType
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.IsByRefLikeAttribute::.ctor() = (01 00 00 00)
.field public int32& modreq(int32) F
}";
var refA = CompileIL(sourceA);
var sourceB =
@"using System;
class Program
{
static void Main()
{
var a = new A();
Console.WriteLine(a.F);
}
}";
var comp = CreateCompilation(sourceB, new[] { refA }, targetFramework: TargetFramework.Net70);
comp.VerifyEmitDiagnostics(
// (7,29): error CS0570: 'A.F' is not supported by the language
// Console.WriteLine(a.F);
Diagnostic(ErrorCode.ERR_BindToBogus, "F").WithArguments("A.F").WithLocation(7, 29));
}
/// <summary>
/// modreq(System.Runtime.InteropServices.InAttribute).
/// Should we allow this modreq() even though it is not generated by the compiler?
/// </summary>
[Fact]
public void RefCustomModifiers_UseSiteDiagnostic_01()
{
var sourceA =
@".class public sealed A extends [mscorlib]System.ValueType
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.IsByRefLikeAttribute::.ctor() = (01 00 00 00)
.field public int32& modreq([mscorlib]System.Runtime.InteropServices.InAttribute) F
}";
var refA = CompileIL(sourceA);
var sourceB =
@"using System;
class Program
{
static void Main()
{
var a = new A();
Console.WriteLine(a.F);
}
}";
var comp = CreateCompilation(sourceB, new[] { refA }, targetFramework: TargetFramework.Net70);
comp.VerifyEmitDiagnostics(
// (7,29): error CS0570: 'A.F' is not supported by the language
// Console.WriteLine(a.F);
Diagnostic(ErrorCode.ERR_BindToBogus, "F").WithArguments("A.F").WithLocation(7, 29));
}
/// <summary>
/// modopt() with missing type.
/// </summary>
[Fact]
public void RefCustomModifiers_UseSiteDiagnostic_03()
{
var sourceA =
@".assembly extern mscorlib { }
.assembly A { }
.class public A
{
}";
var refA = CompileIL(sourceA, prependDefaultHeader: false);
var sourceB =
@".assembly extern A { }
.class public sealed B extends [mscorlib]System.ValueType
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.IsByRefLikeAttribute::.ctor() = (01 00 00 00)
.field public int32& modopt(int8) modopt([A]A) F
}";
var refB = CompileIL(sourceB);
var sourceC =
@"using System;
class Program
{
static void Main()
{
var b = new B();
Console.WriteLine(b.F);
}
}";
var comp = CreateCompilation(sourceC, new[] { refB }, targetFramework: TargetFramework.Net70);
comp.VerifyEmitDiagnostics(
// (7,29): error CS0012: The type 'A' is defined in an assembly that is not referenced. You must add a reference to assembly 'A, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'.
// Console.WriteLine(b.F);
Diagnostic(ErrorCode.ERR_NoTypeDef, "F").WithArguments("A", "A, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null").WithLocation(7, 29));
}
[Fact]
public void MemberRefMetadataDecoder_FindFieldBySignature()
{
var sourceA =
@".class public sealed R<T> extends [mscorlib]System.ValueType
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.IsByRefLikeAttribute::.ctor() = (01 00 00 00)
.field private !0 F1
.field public !0& F1
.field private !0& modopt(int32) F2
.field public !0& modopt(object) F2
.field private int32& F3
.field public int8& F3
}";
var refA = CompileIL(sourceA);
var sourceB =
@"class B
{
static object F1() => new R<object>().F1;
static object F2() => new R<object>().F2;
static int F3() => new R<object>().F3;
}";
var compB = CreateCompilation(sourceB, references: new[] { refA }, targetFramework: TargetFramework.Net70);
var verifier = CompileAndVerify(compB, verify: Verification.Skipped);
// MemberRefMetadataDecoder.FindFieldBySignature() is used to find fields when realIL: true.
verifier.VerifyIL("B.F1", realIL: true, expectedIL:
@"{
// Code size 16 (0x10)
.maxstack 1
.locals init (R<object> V_0)
IL_0000: ldloca.s V_0
IL_0002: initobj ""R<object>""
IL_0008: ldloc.0
IL_0009: ldfld ""ref object R<object>.F1""
IL_000e: ldind.ref
IL_000f: ret
}");
var refB = verifier.Compilation.EmitToImageReference();
var comp = CreateCompilation("", references: new[] { refA, refB });
comp.VerifyEmitDiagnostics();
// Call MemberRefMetadataDecoder.FindFieldBySignature() indirectly from MetadataDecoder.GetSymbolForILToken().
var module = (PEModuleSymbol)comp.GetReferencedAssemblySymbol(refB).Modules[0];
var decoder = new MetadataDecoder(module);
var reader = module.Module.MetadataReader;
var fieldReferences = reader.MemberReferences.
Where(handle => reader.GetString(reader.GetMemberReference(handle).Name) is "F1" or "F2" or "F3").
Select(handle => decoder.GetSymbolForILToken(handle)).
ToArray();
var containingType = fieldReferences[0].ContainingType;
var fieldMembers = containingType.GetMembers().WhereAsArray(m => m.Kind == SymbolKind.Field);
var expectedMembers = new[]
{
"System.Object R<System.Object>.F1",
"ref System.Object R<System.Object>.F1",
"ref modopt(System.Int32) System.Object R<System.Object>.F2",
"ref modopt(System.Object) System.Object R<System.Object>.F2",
"ref System.Int32 R<System.Object>.F3",
"ref System.SByte R<System.Object>.F3"
};
AssertEx.Equal(expectedMembers, fieldMembers.ToTestDisplayStrings());
var expectedReferences = new[]
{
"ref System.Object R<System.Object>.F1",
"ref modopt(System.Object) System.Object R<System.Object>.F2",
"ref System.SByte R<System.Object>.F3"
};
AssertEx.Equal(expectedReferences, fieldReferences.ToTestDisplayStrings());
}
[WorkItem(62596, "https://github.com/dotnet/roslyn/issues/62596")]
[Theory]
[InlineData("class")]
[InlineData("struct")]
[InlineData("record")]
[InlineData("record struct")]
public void NonRefStructContainer(string type)
{
var source =
$@"#pragma warning disable 169
{type} R
{{
ref int F;
}}";
var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10, targetFramework: TargetFramework.Net70);
comp.VerifyEmitDiagnostics(
// (4,5): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater.
// ref int F;
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "ref int").WithArguments("ref fields", "11.0").WithLocation(4, 5),
// (4,13): error CS9059: A ref field can only be declared in a ref struct.
// ref int F;
Diagnostic(ErrorCode.ERR_RefFieldInNonRefStruct, "F").WithLocation(4, 13));
comp = CreateCompilation(source, targetFramework: TargetFramework.Net70);
comp.VerifyEmitDiagnostics(
// (4,13): error CS9059: A ref field can only be declared in a ref struct.
// ref int F;
Diagnostic(ErrorCode.ERR_RefFieldInNonRefStruct, "F").WithLocation(4, 13));
}
/// <summary>
/// Determination of enum underlying type should ignore ref fields
/// and fields with required custom modifiers.
/// </summary>
[Fact]
public void EnumUnderlyingType()
{
var sourceA =
@".class public sealed E extends [mscorlib]System.Enum
{
.field public int64 modreq(object) value1
.field public int32& modopt(object) value2
.field public int32& value3
.field public int16 value4
.field public static literal valuetype E A = int16(0x01)
}";
var refA = CompileIL(sourceA);
var sourceB =
@"class Program
{
static void Main()
{
_ = E.A;
}
}";
var comp = CreateCompilation(sourceB, references: new[] { refA });
comp.VerifyEmitDiagnostics();
var type = (NamedTypeSymbol)comp.GetTypeByMetadataName("E");
Assert.Equal(SpecialType.System_Int16, type.EnumUnderlyingType.SpecialType);
}
private static void VerifyFieldSymbol(FieldSymbol field, string expectedDisplayString, RefKind expectedRefKind, string[] expectedRefCustomModifiers)
{
Assert.Equal(expectedRefKind, field.RefKind);
Assert.Equal(expectedRefCustomModifiers, field.RefCustomModifiers.SelectAsArray(m => m.Modifier.ToTestDisplayString()));
Assert.Equal(expectedDisplayString, field.ToTestDisplayString());
}
[WorkItem(62131, "https://github.com/dotnet/roslyn/issues/62131")]
[CombinatorialData]
[Theory]
public void RuntimeFeature(bool useCompilationReference)
{
var sourceA =
@"namespace System
{
public class Object { }
public abstract class ValueType { }
public class String { }
public struct Void { }
public struct Boolean { }
public struct Int32 { }
public class Attribute { }
public class AttributeUsageAttribute : Attribute
{
public AttributeUsageAttribute(AttributeTargets validOn) { }
public bool AllowMultiple { get; set; }
public bool Inherited { get; set; }
}
public struct Enum { }
public enum AttributeTargets { }
}";
var sourceB =
@"namespace System.Runtime.CompilerServices
{
public static class RuntimeFeature
{
public const string ByRefFields = nameof(ByRefFields);
}
}";
var comp = CreateEmptyCompilation(new[] { sourceA }, parseOptions: TestOptions.Regular10);
var refA = AsReference(comp, useCompilationReference);
comp = CreateEmptyCompilation(new[] { sourceA, sourceB }, parseOptions: TestOptions.Regular10);
var refAB = AsReference(comp, useCompilationReference);
var source =
@"ref struct R<T>
{
public ref T F;
public R(ref T t) { F = ref t; }
}
class Program
{
static ref T F<T>(R<T> r)
{
return ref r.F;
}
}";
comp = CreateEmptyCompilation(source, references: new[] { refA }, parseOptions: TestOptions.Regular10);
comp.VerifyDiagnostics(
// (3,12): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater.
// public ref T F;
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "ref T").WithArguments("ref fields", "11.0").WithLocation(3, 12),
// (3,18): error CS9064: Target runtime doesn't support ref fields.
// public ref T F;
Diagnostic(ErrorCode.ERR_RuntimeDoesNotSupportRefFields, "F").WithLocation(3, 18),
// (10,20): error CS8167: Cannot return by reference a member of parameter 'r' because it is not a ref or out parameter
// return ref r.F;
Diagnostic(ErrorCode.ERR_RefReturnParameter2, "r").WithArguments("r").WithLocation(10, 20));
Assert.False(comp.Assembly.RuntimeSupportsByRefFields);
Assert.False(comp.SupportsRuntimeCapability(RuntimeCapability.ByRefFields));
comp = CreateEmptyCompilation(source, references: new[] { refAB }, parseOptions: TestOptions.Regular10);
comp.VerifyDiagnostics(
// (3,12): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater.
// public ref T F;
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "ref T").WithArguments("ref fields", "11.0").WithLocation(3, 12));
Assert.True(comp.Assembly.RuntimeSupportsByRefFields);
Assert.True(comp.SupportsRuntimeCapability(RuntimeCapability.ByRefFields));
comp = CreateEmptyCompilation(source, references: new[] { refA });
comp.VerifyDiagnostics(
// (3,18): error CS9064: Target runtime doesn't support ref fields.
// public ref T F;
Diagnostic(ErrorCode.ERR_RuntimeDoesNotSupportRefFields, "F").WithLocation(3, 18));
Assert.False(comp.Assembly.RuntimeSupportsByRefFields);
Assert.False(comp.SupportsRuntimeCapability(RuntimeCapability.ByRefFields));
comp = CreateEmptyCompilation(source, references: new[] { refAB });
comp.VerifyDiagnostics();
Assert.True(comp.Assembly.RuntimeSupportsByRefFields);
Assert.True(comp.SupportsRuntimeCapability(RuntimeCapability.ByRefFields));
}
[ConditionalTheory(typeof(CoreClrOnly))]
[CombinatorialData]
public void RefAssembly(bool includePrivateMembers)
{
var sourceA =
@"public ref struct R1<T, U>
{
private ref T _f1;
private ref readonly U _f2;
public R1(ref T t, ref U u)
{
_f1 = ref t;
_f2 = ref u;
}
public override string ToString() => (_f1, _f2).ToString();
}
public ref struct R2<T, U>
{
public ref T F1;
public ref readonly U F2;
public R2(ref T t, ref U u)
{
F1 = ref t;
F2 = ref u;
}
public override string ToString() => (F1, F2).ToString();
}";
var compA = CreateCompilation(sourceA, targetFramework: TargetFramework.Net70);
var emitOptions = Microsoft.CodeAnalysis.Emit.EmitOptions.Default.WithEmitMetadataOnly(true).WithIncludePrivateMembers(includePrivateMembers);
var refA = compA.EmitToImageReference(emitOptions);
var sourceB =
@"using System;
public class B
{
public static void M()
{
int i = 1;
double d = 2.0;
var r1 = new R1<int, double>(ref i, ref d);
var r2 = new R2<double, int>(ref d, ref i);
i = 3;
d = 4.0;
Console.WriteLine((r1.ToString(), r2.ToString()));
}
}";
var compB = CreateCompilation(sourceB, references: new[] { refA }, targetFramework: TargetFramework.Net70);
var refB = compB.EmitToImageReference();
verifyFields(compB.GetMember<NamedTypeSymbol>("R1"), new[] { "ref T R1<T, U>._f1", "ref readonly U R1<T, U>._f2" });
verifyFields(compB.GetMember<NamedTypeSymbol>("R2"), new[] { "ref T R2<T, U>.F1", "ref readonly U R2<T, U>.F2" });
var sourceC =
@"class Program
{
static void Main()
{
B.M();
}
}";
// Requires full assembly for A at runtime.
CompileAndVerify(
sourceC,
references: new[] { refB, compA.EmitToImageReference() },
targetFramework: TargetFramework.Net70,
verify: Verification.Skipped,
expectedOutput: @"((3, 4), (4, 3))");
static void verifyFields(NamedTypeSymbol type, string[] expectedFields)
{
var actualFields = type.GetMembers().OfType<FieldSymbol>().Select(f => f.ToTestDisplayString()).ToList();
AssertEx.Equal(actualFields, expectedFields);
}
}
[Theory]
[InlineData(LanguageVersion.CSharp10)]
[InlineData(LanguageVersion.CSharp11)]
[InlineData(LanguageVersion.Latest)]
public void RequiredField_01(LanguageVersion languageVersion)
{
var source = """
#pragma warning disable 169
#pragma warning disable 649
ref struct R<T, U>
{
public required ref T F1;
public required ref readonly U F2;
}
""";
var comp = CreateCompilation(source, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion), targetFramework: TargetFramework.Net70);
if (languageVersion == LanguageVersion.CSharp10)
{
comp.VerifyEmitDiagnostics(
// (5,21): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater.
// public required ref T F1;
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "ref T").WithArguments("ref fields", "11.0").WithLocation(5, 21),
// (5,27): error CS8936: Feature 'required members' is not available in C# 10.0. Please use language version 11.0 or greater.
// public required ref T F1;
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "F1").WithArguments("required members", "11.0").WithLocation(5, 27),
// (6,21): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater.
// public required ref readonly U F2;
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "ref readonly U").WithArguments("ref fields", "11.0").WithLocation(6, 21),
// (6,36): error CS8936: Feature 'required members' is not available in C# 10.0. Please use language version 11.0 or greater.
// public required ref readonly U F2;
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "F2").WithArguments("required members", "11.0").WithLocation(6, 36));
}
else
{
comp.VerifyEmitDiagnostics();
}
}
[Theory]
[CombinatorialData]
public void RequiredField_02(bool useCompilationReference)
{
var sourceA = """
public ref struct R<T, U>
{
private static U _u;
public required ref T F1;
public required ref readonly U F2;
public R()
{
F2 = ref _u;
}
public R(ref T t)
{
F1 = ref t;
}
public R(ref T t, ref U u)
{
F1 = ref t;
F2 = ref u;
}
}
""";
var comp = CreateCompilation(sourceA, targetFramework: TargetFramework.Net70);
var refA = AsReference(comp, useCompilationReference);
var sourceB = """
class Program
{
static void Main()
{
int i = 1;
double d = 2.0;
scoped R<int, double> r;
r = default;
r = new(); // 1
r = new() { }; // 2
r = new() { F1 = ref i }; // 3
r = new() { F2 = ref d }; // 4
r = new() { F1 = ref i, F2 = ref d };
r = new R<int, double>(); // 5
r = new R<int, double> { }; // 6
r = new(ref i); // 7
r = new(ref i, ref d);
r = new(ref i) { F1 = ref i }; // 8
r = new(ref i) { F2 = ref d }; // 9
}
}
""";
comp = CreateCompilation(sourceB, references: new[] { refA }, targetFramework: TargetFramework.Net70);
comp.VerifyEmitDiagnostics(
// (9,13): error CS9035: Required member 'R<int, double>.F2' must be set in the object initializer or attribute constructor.
// r = new(); // 1
Diagnostic(ErrorCode.ERR_RequiredMemberMustBeSet, "new").WithArguments("R<int, double>.F2").WithLocation(9, 13),
// (9,13): error CS9035: Required member 'R<int, double>.F1' must be set in the object initializer or attribute constructor.
// r = new(); // 1
Diagnostic(ErrorCode.ERR_RequiredMemberMustBeSet, "new").WithArguments("R<int, double>.F1").WithLocation(9, 13),
// (10,13): error CS9035: Required member 'R<int, double>.F2' must be set in the object initializer or attribute constructor.
// r = new() { }; // 2
Diagnostic(ErrorCode.ERR_RequiredMemberMustBeSet, "new").WithArguments("R<int, double>.F2").WithLocation(10, 13),
// (10,13): error CS9035: Required member 'R<int, double>.F1' must be set in the object initializer or attribute constructor.
// r = new() { }; // 2
Diagnostic(ErrorCode.ERR_RequiredMemberMustBeSet, "new").WithArguments("R<int, double>.F1").WithLocation(10, 13),
// (11,13): error CS9035: Required member 'R<int, double>.F2' must be set in the object initializer or attribute constructor.
// r = new() { F1 = ref i };
Diagnostic(ErrorCode.ERR_RequiredMemberMustBeSet, "new").WithArguments("R<int, double>.F2").WithLocation(11, 13),
// (12,13): error CS9035: Required member 'R<int, double>.F1' must be set in the object initializer or attribute constructor.
// r = new() { F2 = ref d }; // 3
Diagnostic(ErrorCode.ERR_RequiredMemberMustBeSet, "new").WithArguments("R<int, double>.F1").WithLocation(12, 13),
// (14,17): error CS9035: Required member 'R<int, double>.F2' must be set in the object initializer or attribute constructor.
// r = new R<int, double>(); // 4
Diagnostic(ErrorCode.ERR_RequiredMemberMustBeSet, "R<int, double>").WithArguments("R<int, double>.F2").WithLocation(14, 17),
// (14,17): error CS9035: Required member 'R<int, double>.F1' must be set in the object initializer or attribute constructor.
// r = new R<int, double>(); // 4
Diagnostic(ErrorCode.ERR_RequiredMemberMustBeSet, "R<int, double>").WithArguments("R<int, double>.F1").WithLocation(14, 17),
// (15,17): error CS9035: Required member 'R<int, double>.F2' must be set in the object initializer or attribute constructor.
// r = new R<int, double> { } // 5
Diagnostic(ErrorCode.ERR_RequiredMemberMustBeSet, "R<int, double>").WithArguments("R<int, double>.F2").WithLocation(15, 17),
// (15,17): error CS9035: Required member 'R<int, double>.F1' must be set in the object initializer or attribute constructor.
// r = new R<int, double> { } // 5
Diagnostic(ErrorCode.ERR_RequiredMemberMustBeSet, "R<int, double>").WithArguments("R<int, double>.F1").WithLocation(15, 17),
// (16,13): error CS9035: Required member 'R<int, double>.F2' must be set in the object initializer or attribute constructor.
// r = new(ref i); // 6
Diagnostic(ErrorCode.ERR_RequiredMemberMustBeSet, "new").WithArguments("R<int, double>.F2").WithLocation(16, 13),
// (16,13): error CS9035: Required member 'R<int, double>.F1' must be set in the object initializer or attribute constructor.
// r = new(ref i); // 6
Diagnostic(ErrorCode.ERR_RequiredMemberMustBeSet, "new").WithArguments("R<int, double>.F1").WithLocation(16, 13),
// (17,13): error CS9035: Required member 'R<int, double>.F2' must be set in the object initializer or attribute constructor.
// r = new(ref i, ref d);
Diagnostic(ErrorCode.ERR_RequiredMemberMustBeSet, "new").WithArguments("R<int, double>.F2").WithLocation(17, 13),
// (17,13): error CS9035: Required member 'R<int, double>.F1' must be set in the object initializer or attribute constructor.
// r = new(ref i, ref d);
Diagnostic(ErrorCode.ERR_RequiredMemberMustBeSet, "new").WithArguments("R<int, double>.F1").WithLocation(17, 13),
// (18,13): error CS9035: Required member 'R<int, double>.F2' must be set in the object initializer or attribute constructor.
// r = new(ref i) { F1 = ref i }; // 7
Diagnostic(ErrorCode.ERR_RequiredMemberMustBeSet, "new").WithArguments("R<int, double>.F2").WithLocation(18, 13),
// (19,13): error CS9035: Required member 'R<int, double>.F1' must be set in the object initializer or attribute constructor.
// r = new(ref i) { F2 = ref d };
Diagnostic(ErrorCode.ERR_RequiredMemberMustBeSet, "new").WithArguments("R<int, double>.F1").WithLocation(19, 13));
}
/// <summary>
/// Ref fields of ref struct type are not supported.
/// </summary>
[Fact]
public void RefFieldTypeRefStruct_01()
{
var source =
@"#pragma warning disable 169
ref struct R1<T>
{
}
ref struct R2<T>
{
public ref R1<T> F;
}
class Program
{
static void F(ref R1<int> r1)
{
var r2 = new R2<int>();
r2.F = ref r1;
}
}";
var comp = CreateCompilation(new[] { source, UnscopedRefAttributeDefinition }, targetFramework: TargetFramework.Net70);
comp.VerifyEmitDiagnostics(
// (8,12): error CS9050: A ref field cannot refer to a ref struct.
// public ref R1<T> F;
Diagnostic(ErrorCode.ERR_RefFieldCannotReferToRefStruct, "ref R1<T>").WithLocation(8, 12),
// (15,9): error CS9079: Cannot ref-assign 'r1' to 'F' because 'r1' can only escape the current method through a return statement.
// r2.F = ref r1;
Diagnostic(ErrorCode.ERR_RefAssignReturnOnly, "r2.F = ref r1").WithArguments("F", "r1").WithLocation(15, 9));
}
/// <summary>
/// Ref fields of ref struct type are not supported.
/// </summary>
[Fact]
public void RefFieldTypeRefStruct_02()
{
var sourceA =
@".class public sealed R1 extends [mscorlib]System.ValueType
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.IsByRefLikeAttribute::.ctor() = (01 00 00 00)
}
.class public sealed R2 extends [mscorlib]System.ValueType
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.IsByRefLikeAttribute::.ctor() = (01 00 00 00)
.field public valuetype R1& F
}
";
var refA = CompileIL(sourceA);
var sourceB =
@"class Program
{
static void F(ref R1 r1)
{
var r2 = new R2();
r2.F = ref r1;
}
}";
var comp = CreateCompilation(sourceB, references: new[] { refA }, targetFramework: TargetFramework.Net70);
comp.VerifyEmitDiagnostics(
// (6,12): error CS0570: 'R2.F' is not supported by the language
// r2.F = ref r1;
Diagnostic(ErrorCode.ERR_BindToBogus, "F").WithArguments("R2.F").WithLocation(6, 12));
}
[Fact]
public void RefFields_RefEscape()
{
var source =
@"ref struct R<T>
{
ref T F;
R(ref T t) { F = ref t; }
ref T F0() => ref this.F;
static ref T F1(R<T> r1)
{
return ref r1.F;
}
static ref T F2(T t)
{
var r2 = new R<T>(ref t);
return ref r2.F;
}
}";
var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10, targetFramework: TargetFramework.Net70);
comp.VerifyDiagnostics(
// (3,5): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater.
// ref T F;
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "ref T").WithArguments("ref fields", "11.0").WithLocation(3, 5),
// (13,20): error CS8352: Cannot use variable 'r2' in this context because it may expose referenced variables outside of their declaration scope
// return ref r2.F;
Diagnostic(ErrorCode.ERR_EscapeVariable, "r2.F").WithArguments("r2").WithLocation(13, 20));
comp = CreateCompilation(source, targetFramework: TargetFramework.Net70);
comp.VerifyEmitDiagnostics(
// (13,20): error CS8352: Cannot use variable 'r2' in this context because it may expose referenced variables outside of their declaration scope
// return ref r2.F;
Diagnostic(ErrorCode.ERR_EscapeVariable, "r2.F").WithArguments("r2").WithLocation(13, 20));
}
[Fact]
public void RefFields_RefEscape_UnsafeContext()
{
var source =
@"ref struct R<T>
{
ref T F;
R(ref T t) { F = ref t; }
ref T F0() => ref this.F;
static unsafe ref T F2(T t)
{
var r2 = new R<T>(ref t);
return ref r2.F;
}
}";
var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70, options: TestOptions.UnsafeDebugDll);
comp.VerifyEmitDiagnostics(
// (9,20): warning CS9077: Use of variable 'r2' in this context may expose referenced variables outside of their declaration scope
// return ref r2.F;
Diagnostic(ErrorCode.WRN_EscapeVariable, "r2.F").WithArguments("r2").WithLocation(9, 20));
var verifier = CompileAndVerify(comp, verify: Verification.Skipped);
verifier.VerifyIL("R<T>.F2", @"
{
// Code size 21 (0x15)
.maxstack 1
.locals init (R<T> V_0, //r2
T& V_1)
IL_0000: nop
IL_0001: ldarga.s V_0
IL_0003: newobj ""R<T>..ctor(ref T)""
IL_0008: stloc.0
IL_0009: ldloca.s V_0
IL_000b: ldfld ""ref T R<T>.F""
IL_0010: stloc.1
IL_0011: br.s IL_0013
IL_0013: ldloc.1
IL_0014: ret
}
");
}
[Fact]
public void RefFields_RefReassignment_01()
{
var source =
@"ref struct R<T>
{
ref T F;
R(ref T t) { F = ref t; }
R<T> F0(ref T t)
{
F = ref t;
return this;
}
static R<T> F1(R<T> r1, ref T t)
{
r1.F = ref t;
return r1;
}
static R<T> F2(R<T> r2)
{
T t = default;
r2.F = ref t;
return r2;
}
}";
var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10, targetFramework: TargetFramework.Net70);
comp.VerifyDiagnostics(
// (3,5): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater.
// ref T F;
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "ref T").WithArguments("ref fields", "11.0").WithLocation(3, 5),
// (7,9): error CS9079: Cannot ref-assign 't' to 'F' because 't' can only escape the current method through a return statement.
// F = ref t;
Diagnostic(ErrorCode.ERR_RefAssignReturnOnly, "F = ref t").WithArguments("F", "t").WithLocation(7, 9),
// (12,9): error CS9079: Cannot ref-assign 't' to 'F' because 't' can only escape the current method through a return statement.
// r1.F = ref t;
Diagnostic(ErrorCode.ERR_RefAssignReturnOnly, "r1.F = ref t").WithArguments("F", "t").WithLocation(12, 9),
// (18,9): error CS8374: Cannot ref-assign 't' to 'F' because 't' has a narrower escape scope than 'F'.
// r2.F = ref t;
Diagnostic(ErrorCode.ERR_RefAssignNarrower, "r2.F = ref t").WithArguments("F", "t").WithLocation(18, 9)
);
comp = CreateCompilation(source, targetFramework: TargetFramework.Net70);
comp.VerifyEmitDiagnostics(
// (7,9): error CS9079: Cannot ref-assign 't' to 'F' because 't' can only escape the current method through a return statement.
// F = ref t;
Diagnostic(ErrorCode.ERR_RefAssignReturnOnly, "F = ref t").WithArguments("F", "t").WithLocation(7, 9),
// (12,9): error CS9079: Cannot ref-assign 't' to 'F' because 't' can only escape the current method through a return statement.
// r1.F = ref t;
Diagnostic(ErrorCode.ERR_RefAssignReturnOnly, "r1.F = ref t").WithArguments("F", "t").WithLocation(12, 9),
// (18,9): error CS8374: Cannot ref-assign 't' to 'F' because 't' has a narrower escape scope than 'F'.
// r2.F = ref t;
Diagnostic(ErrorCode.ERR_RefAssignNarrower, "r2.F = ref t").WithArguments("F", "t").WithLocation(18, 9)
);
}
[Fact]
[WorkItem(63434, "https://github.com/dotnet/roslyn/issues/63434")]
public void RefFields_RefReassignment_02()
{
var source =
@"
using System;
class Program
{
static void Main()
{
int i = 42;
var r = new R() { Field = ref i };
Console.WriteLine(r.Field);
i = 43;
Console.WriteLine(r.Field);
}
}
ref struct R
{
public ref int Field;
}
";
var comp = CreateCompilation(source, options: TestOptions.ReleaseExe, targetFramework: TargetFramework.Net70);
CompileAndVerify(comp, verify: Verification.Skipped, expectedOutput: IncludeExpectedOutput(
@"42
43")).VerifyDiagnostics().
VerifyIL("Program.Main",
@"
{
// Code size 48 (0x30)
.maxstack 2
.locals init (int V_0, //i
R V_1)
IL_0000: ldc.i4.s 42
IL_0002: stloc.0
IL_0003: ldloca.s V_1
IL_0005: initobj ""R""
IL_000b: ldloca.s V_1
IL_000d: ldloca.s V_0
IL_000f: stfld ""ref int R.Field""
IL_0014: ldloc.1
IL_0015: dup
IL_0016: ldfld ""ref int R.Field""
IL_001b: ldind.i4
IL_001c: call ""void System.Console.WriteLine(int)""
IL_0021: ldc.i4.s 43
IL_0023: stloc.0
IL_0024: ldfld ""ref int R.Field""
IL_0029: ldind.i4
IL_002a: call ""void System.Console.WriteLine(int)""
IL_002f: ret
}
");
}
[Fact]
public void RefFields_RefReassignment_03()
{
var source =
@"
using System;
class Program
{
static void Main()
{
int i = 42;
var r = new R();
r.Field = ref i;
Console.WriteLine(r.Field);
}
}
ref struct R
{
public ref int Field;
}
";
var comp = CreateCompilation(source, options: TestOptions.ReleaseExe, targetFramework: TargetFramework.Net70);
comp.VerifyDiagnostics(
// (10,9): error CS8374: Cannot ref-assign 'i' to 'Field' because 'i' has a narrower escape scope than 'Field'.
// r.Field = ref i;
Diagnostic(ErrorCode.ERR_RefAssignNarrower, "r.Field = ref i").WithArguments("Field", "i").WithLocation(10, 9)
);
}
[Fact]
[WorkItem(63434, "https://github.com/dotnet/roslyn/issues/63434")]
public void RefFields_RefReassignment_04()
{
var source =
@"
using System;
class Program
{
static void Main()
{
int i = 42;
Test(ref i);
}
static void Test(ref int i)
{
var r = new R() { Field = ref i };
Console.WriteLine(r.Field);
}
}
ref struct R
{
public ref int Field;
}
";
var comp = CreateCompilation(source, options: TestOptions.ReleaseExe, targetFramework: TargetFramework.Net70);
CompileAndVerify(comp, verify: Verification.Skipped, expectedOutput: IncludeExpectedOutput("42")).VerifyDiagnostics().
VerifyIL("Program.Test",
@"
{
// Code size 29 (0x1d)
.maxstack 2
.locals init (R V_0)
IL_0000: ldloca.s V_0
IL_0002: initobj ""R""
IL_0008: ldloca.s V_0
IL_000a: ldarg.0
IL_000b: stfld ""ref int R.Field""
IL_0010: ldloc.0
IL_0011: ldfld ""ref int R.Field""
IL_0016: ldind.i4
IL_0017: call ""void System.Console.WriteLine(int)""
IL_001c: ret
}
");
}
[Fact]
public void RefFields_RefReassignment_05()
{
var source =
@"
using System;
class Program
{
static void Main()
{
int i = 42;
Test(ref i);
}
static void Test(ref int i)
{
scoped var r = new R();
r.Field = ref i;
Console.WriteLine(r.Field);
}
}
ref struct R
{
public ref int Field;
}
";
var comp = CreateCompilation(source, options: TestOptions.ReleaseExe, targetFramework: TargetFramework.Net70);
CompileAndVerify(comp, verify: Verification.Skipped, expectedOutput: IncludeExpectedOutput("42")).VerifyDiagnostics().
VerifyIL("Program.Test",
@"
{
// Code size 29 (0x1d)
.maxstack 2
.locals init (R V_0) //r
IL_0000: ldloca.s V_0
IL_0002: initobj ""R""
IL_0008: ldloca.s V_0
IL_000a: ldarg.0
IL_000b: stfld ""ref int R.Field""
IL_0010: ldloc.0
IL_0011: ldfld ""ref int R.Field""
IL_0016: ldind.i4
IL_0017: call ""void System.Console.WriteLine(int)""
IL_001c: ret
}
");
}
[Fact]
public void RefThis()
{
var source =
@"struct S<T>
{
ref S<T> F() => ref this;
}
ref struct R<T>
{
ref R<T> F() => ref this;
}";
var expectedDiagnostics = new DiagnosticDescription[]
{
// (3,25): error CS8170: Struct members cannot return 'this' or other instance members by reference
// ref S<T> F() => ref this;
Diagnostic(ErrorCode.ERR_RefReturnStructThis, "this").WithLocation(3, 25),
// (7,25): error CS8170: Struct members cannot return 'this' or other instance members by reference
// ref R<T> F() => ref this;
Diagnostic(ErrorCode.ERR_RefReturnStructThis, "this").WithLocation(7, 25)
};
var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10);
comp.VerifyDiagnostics(expectedDiagnostics);
comp = CreateCompilation(source);
comp.VerifyDiagnostics(expectedDiagnostics);
}
[Fact]
public void RefThis_UnsafeContext()
{
var source =
@"struct S<T>
{
unsafe ref S<T> F() => ref this;
}
ref struct R<T>
{
unsafe ref R<T> F() => ref this;
}";
var comp = CreateCompilation(source, options: TestOptions.UnsafeDebugDll);
comp.VerifyEmitDiagnostics(
// (3,32): warning CS9081: Struct member returns 'this' or other instance members by reference
// unsafe ref S<T> F() => ref this;
Diagnostic(ErrorCode.WRN_RefReturnStructThis, "this").WithLocation(3, 32),
// (7,32): warning CS9081: Struct member returns 'this' or other instance members by reference
// unsafe ref R<T> F() => ref this;
Diagnostic(ErrorCode.WRN_RefReturnStructThis, "this").WithLocation(7, 32)
);
}
[Fact]
public void RefParameter()
{
var source =
@"class C { }
struct S { }
ref struct R { }
class Program
{
static ref C F1(ref C c) => ref c;
static ref S F2(ref S s) => ref s;
static ref R F3(ref R r) => ref r;
static ref readonly C F4(in C c) => ref c;
static ref readonly S F5(in S s) => ref s;
static ref readonly R F6(in R r) => ref r;
static ref C F7(out C c) { c = default; return ref c; } // 1
static ref S F8(out S s) { s = default; return ref s; } // 2
static ref R F9(out R r) { r = default; return ref r; } // 3
}";
var expectedLegacyDiagnostics = new DiagnosticDescription[]
{
};
var expectedUpdatedDiagnostics = new DiagnosticDescription[]
{
// (12,56): error CS9075: Cannot return a parameter by reference 'c' because it is scoped to the current method
// static ref C F7(out C c) { c = default; return ref c; } // 1
Diagnostic(ErrorCode.ERR_RefReturnScopedParameter, "c").WithArguments("c").WithLocation(12, 56),
// (13,56): error CS9075: Cannot return a parameter by reference 's' because it is scoped to the current method
// static ref S F8(out S s) { s = default; return ref s; } // 2
Diagnostic(ErrorCode.ERR_RefReturnScopedParameter, "s").WithArguments("s").WithLocation(13, 56),
// (14,56): error CS9075: Cannot return a parameter by reference 'r' because it is scoped to the current method
// static ref R F9(out R r) { r = default; return ref r; } // 3
Diagnostic(ErrorCode.ERR_RefReturnScopedParameter, "r").WithArguments("r").WithLocation(14, 56)
};
var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10);
comp.VerifyDiagnostics(comp.Assembly.RuntimeSupportsByRefFields ? expectedUpdatedDiagnostics : expectedLegacyDiagnostics);
comp = CreateCompilation(source);
comp.VerifyEmitDiagnostics(expectedUpdatedDiagnostics);
}
[Fact]
public void MethodInvocation_Lvalue_01()
{
var source =
@"struct S
{
internal ref T F0<T>(T t) => throw null;
internal ref T F1<T>(ref T t) => throw null;
internal ref T F2<T>(in T t) => throw null;
internal ref T F3<T>(out T t) => throw null;
}
class Program
{
static ref T F00<T>() { S s = default; T t = default; return ref s.F0(t); }
static ref T F01<T>() { S s = default; T t = default; return ref s.F1(ref t); } // 1
static ref T F02<T>() { S s = default; T t = default; return ref s.F2(in t); } // 2
static ref T F03<T>() { S s = default; T t = default; return ref s.F2(t); } // 3
static ref T F04<T>() { S s = default; T t = default; return ref s.F3(out t); }
static ref T F10<T>(ref T t) { S s = default; return ref s.F0(t); }
static ref T F11<T>(ref T t) { S s = default; return ref s.F1(ref t); }
static ref T F12<T>(ref T t) { S s = default; return ref s.F2(in t); }
static ref T F13<T>(ref T t) { S s = default; return ref s.F2(t); }
static ref T F14<T>(ref T t) { S s = default; return ref s.F3(out t); }
static ref T F20<T>(in T t) { S s = default; return ref s.F0(t); }
static ref T F22<T>(in T t) { S s = default; return ref s.F2(in t); }
static ref T F23<T>(in T t) { S s = default; return ref s.F2(t); }
static ref T F30<T>(out T t) { S s = default; t = default; return ref s.F0(t); }
static ref T F31<T>(out T t) { S s = default; t = default; return ref s.F1(ref t); } // 4
static ref T F32<T>(out T t) { S s = default; t = default; return ref s.F2(in t); } // 5
static ref T F33<T>(out T t) { S s = default; t = default; return ref s.F2(t); } // 6
static ref T F34<T>(out T t) { S s = default; t = default; return ref s.F3(out t); }
static ref T F41<T>(ref S s) { T t = default; return ref s.F0(t); }
static ref T F42<T>(in S s) { T t = default; return ref s.F1(ref t); } // 7
static ref T F43<T>(out S s) { s = default; T t = default; return ref s.F2(in t); } // 8
static ref T F51<T>(ref S s, ref T t) { return ref s.F0(t); }
static ref T F52<T>(in S s, ref T t) { return ref s.F1(ref t); }
static ref T F53<T>(out S s, ref T t) { s = default; return ref s.F2(in t); }
}";
var expectedLegacyDiagnostics = new DiagnosticDescription[]
{
// (11,70): error CS8347: Cannot use a result of 'S.F1<T>(ref T)' in this context because it may expose variables referenced by parameter 't' outside of their declaration scope
// static ref T F01<T>() { S s = default; T t = default; return ref s.F1(ref t); } // 1
Diagnostic(ErrorCode.ERR_EscapeCall, "s.F1(ref t)").WithArguments("S.F1<T>(ref T)", "t").WithLocation(11, 70),
// (11,79): error CS8168: Cannot return local 't' by reference because it is not a ref local
// static ref T F01<T>() { S s = default; T t = default; return ref s.F1(ref t); } // 1
Diagnostic(ErrorCode.ERR_RefReturnLocal, "t").WithArguments("t").WithLocation(11, 79),
// (12,70): error CS8347: Cannot use a result of 'S.F2<T>(in T)' in this context because it may expose variables referenced by parameter 't' outside of their declaration scope
// static ref T F02<T>() { S s = default; T t = default; return ref s.F2(in t); } // 2
Diagnostic(ErrorCode.ERR_EscapeCall, "s.F2(in t)").WithArguments("S.F2<T>(in T)", "t").WithLocation(12, 70),
// (12,78): error CS8168: Cannot return local 't' by reference because it is not a ref local
// static ref T F02<T>() { S s = default; T t = default; return ref s.F2(in t); } // 2
Diagnostic(ErrorCode.ERR_RefReturnLocal, "t").WithArguments("t").WithLocation(12, 78),
// (13,70): error CS8347: Cannot use a result of 'S.F2<T>(in T)' in this context because it may expose variables referenced by parameter 't' outside of their declaration scope
// static ref T F03<T>() { S s = default; T t = default; return ref s.F2(t); } // 3
Diagnostic(ErrorCode.ERR_EscapeCall, "s.F2(t)").WithArguments("S.F2<T>(in T)", "t").WithLocation(13, 70),
// (13,75): error CS8168: Cannot return local 't' by reference because it is not a ref local
// static ref T F03<T>() { S s = default; T t = default; return ref s.F2(t); } // 3
Diagnostic(ErrorCode.ERR_RefReturnLocal, "t").WithArguments("t").WithLocation(13, 75),
// (14,70): error CS8347: Cannot use a result of 'S.F3<T>(out T)' in this context because it may expose variables referenced by parameter 't' outside of their declaration scope
// static ref T F04<T>() { S s = default; T t = default; return ref s.F3(out t); }
Diagnostic(ErrorCode.ERR_EscapeCall, "s.F3(out t)").WithArguments("S.F3<T>(out T)", "t").WithLocation(14, 70),
// (14,79): error CS8168: Cannot return local 't' by reference because it is not a ref local
// static ref T F04<T>() { S s = default; T t = default; return ref s.F3(out t); }
Diagnostic(ErrorCode.ERR_RefReturnLocal, "t").WithArguments("t").WithLocation(14, 79),
// (29,61): error CS8347: Cannot use a result of 'S.F1<T>(ref T)' in this context because it may expose variables referenced by parameter 't' outside of their declaration scope
// static ref T F42<T>(in S s) { T t = default; return ref s.F1(ref t); } // 7
Diagnostic(ErrorCode.ERR_EscapeCall, "s.F1(ref t)").WithArguments("S.F1<T>(ref T)", "t").WithLocation(29, 61),
// (29,70): error CS8168: Cannot return local 't' by reference because it is not a ref local
// static ref T F42<T>(in S s) { T t = default; return ref s.F1(ref t); } // 7
Diagnostic(ErrorCode.ERR_RefReturnLocal, "t").WithArguments("t").WithLocation(29, 70),
// (30,75): error CS8347: Cannot use a result of 'S.F2<T>(in T)' in this context because it may expose variables referenced by parameter 't' outside of their declaration scope
// static ref T F43<T>(out S s) { s = default; T t = default; return ref s.F2(in t); } // 8
Diagnostic(ErrorCode.ERR_EscapeCall, "s.F2(in t)").WithArguments("S.F2<T>(in T)", "t").WithLocation(30, 75),
// (30,83): error CS8168: Cannot return local 't' by reference because it is not a ref local
// static ref T F43<T>(out S s) { s = default; T t = default; return ref s.F2(in t); } // 8
Diagnostic(ErrorCode.ERR_RefReturnLocal, "t").WithArguments("t").WithLocation(30, 83)
};
var expectedUpdatedDiagnostics = new DiagnosticDescription[]
{
// (11,70): error CS8347: Cannot use a result of 'S.F1<T>(ref T)' in this context because it may expose variables referenced by parameter 't' outside of their declaration scope
// static ref T F01<T>() { S s = default; T t = default; return ref s.F1(ref t); } // 1
Diagnostic(ErrorCode.ERR_EscapeCall, "s.F1(ref t)").WithArguments("S.F1<T>(ref T)", "t").WithLocation(11, 70),
// (11,79): error CS8168: Cannot return local 't' by reference because it is not a ref local
// static ref T F01<T>() { S s = default; T t = default; return ref s.F1(ref t); } // 1
Diagnostic(ErrorCode.ERR_RefReturnLocal, "t").WithArguments("t").WithLocation(11, 79),
// (12,70): error CS8347: Cannot use a result of 'S.F2<T>(in T)' in this context because it may expose variables referenced by parameter 't' outside of their declaration scope
// static ref T F02<T>() { S s = default; T t = default; return ref s.F2(in t); } // 2
Diagnostic(ErrorCode.ERR_EscapeCall, "s.F2(in t)").WithArguments("S.F2<T>(in T)", "t").WithLocation(12, 70),
// (12,78): error CS8168: Cannot return local 't' by reference because it is not a ref local
// static ref T F02<T>() { S s = default; T t = default; return ref s.F2(in t); } // 2
Diagnostic(ErrorCode.ERR_RefReturnLocal, "t").WithArguments("t").WithLocation(12, 78),
// (13,70): error CS8347: Cannot use a result of 'S.F2<T>(in T)' in this context because it may expose variables referenced by parameter 't' outside of their declaration scope
// static ref T F03<T>() { S s = default; T t = default; return ref s.F2(t); } // 3
Diagnostic(ErrorCode.ERR_EscapeCall, "s.F2(t)").WithArguments("S.F2<T>(in T)", "t").WithLocation(13, 70),
// (13,75): error CS8168: Cannot return local 't' by reference because it is not a ref local
// static ref T F03<T>() { S s = default; T t = default; return ref s.F2(t); } // 3
Diagnostic(ErrorCode.ERR_RefReturnLocal, "t").WithArguments("t").WithLocation(13, 75),
// (24,75): error CS8347: Cannot use a result of 'S.F1<T>(ref T)' in this context because it may expose variables referenced by parameter 't' outside of their declaration scope
// static ref T F31<T>(out T t) { S s = default; t = default; return ref s.F1(ref t); } // 4
Diagnostic(ErrorCode.ERR_EscapeCall, "s.F1(ref t)").WithArguments("S.F1<T>(ref T)", "t").WithLocation(24, 75),
// (24,84): error CS9075: Cannot return a parameter by reference 't' because it is scoped to the current method
// static ref T F31<T>(out T t) { S s = default; t = default; return ref s.F1(ref t); } // 4
Diagnostic(ErrorCode.ERR_RefReturnScopedParameter, "t").WithArguments("t").WithLocation(24, 84),
// (25,75): error CS8347: Cannot use a result of 'S.F2<T>(in T)' in this context because it may expose variables referenced by parameter 't' outside of their declaration scope
// static ref T F32<T>(out T t) { S s = default; t = default; return ref s.F2(in t); } // 5
Diagnostic(ErrorCode.ERR_EscapeCall, "s.F2(in t)").WithArguments("S.F2<T>(in T)", "t").WithLocation(25, 75),
// (25,83): error CS9075: Cannot return a parameter by reference 't' because it is scoped to the current method
// static ref T F32<T>(out T t) { S s = default; t = default; return ref s.F2(in t); } // 5
Diagnostic(ErrorCode.ERR_RefReturnScopedParameter, "t").WithArguments("t").WithLocation(25, 83),
// (26,75): error CS8347: Cannot use a result of 'S.F2<T>(in T)' in this context because it may expose variables referenced by parameter 't' outside of their declaration scope
// static ref T F33<T>(out T t) { S s = default; t = default; return ref s.F2(t); } // 6
Diagnostic(ErrorCode.ERR_EscapeCall, "s.F2(t)").WithArguments("S.F2<T>(in T)", "t").WithLocation(26, 75),
// (26,80): error CS9075: Cannot return a parameter by reference 't' because it is scoped to the current method
// static ref T F33<T>(out T t) { S s = default; t = default; return ref s.F2(t); } // 6
Diagnostic(ErrorCode.ERR_RefReturnScopedParameter, "t").WithArguments("t").WithLocation(26, 80),
// (29,61): error CS8347: Cannot use a result of 'S.F1<T>(ref T)' in this context because it may expose variables referenced by parameter 't' outside of their declaration scope
// static ref T F42<T>(in S s) { T t = default; return ref s.F1(ref t); } // 7
Diagnostic(ErrorCode.ERR_EscapeCall, "s.F1(ref t)").WithArguments("S.F1<T>(ref T)", "t").WithLocation(29, 61),
// (29,70): error CS8168: Cannot return local 't' by reference because it is not a ref local
// static ref T F42<T>(in S s) { T t = default; return ref s.F1(ref t); } // 7
Diagnostic(ErrorCode.ERR_RefReturnLocal, "t").WithArguments("t").WithLocation(29, 70),
// (30,75): error CS8347: Cannot use a result of 'S.F2<T>(in T)' in this context because it may expose variables referenced by parameter 't' outside of their declaration scope
// static ref T F43<T>(out S s) { s = default; T t = default; return ref s.F2(in t); } // 8
Diagnostic(ErrorCode.ERR_EscapeCall, "s.F2(in t)").WithArguments("S.F2<T>(in T)", "t").WithLocation(30, 75),
// (30,83): error CS8168: Cannot return local 't' by reference because it is not a ref local
// static ref T F43<T>(out S s) { s = default; T t = default; return ref s.F2(in t); } // 8
Diagnostic(ErrorCode.ERR_RefReturnLocal, "t").WithArguments("t").WithLocation(30, 83)
};
var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10);
comp.VerifyDiagnostics(comp.Assembly.RuntimeSupportsByRefFields ? expectedUpdatedDiagnostics : expectedLegacyDiagnostics);
comp = CreateCompilation(source);
comp.VerifyEmitDiagnostics(expectedUpdatedDiagnostics);
}
[Fact]
public void MethodInvocation_Lvalue_02()
{
var source =
@"class C
{
ref T F0<T>(T t) => throw null;
ref T F1<T>(ref T t) => throw null;
ref T F2<T>(in T t) => throw null;
ref T F3<T>(out T t) => throw null;
ref T F00<T>() { T t = default; return ref F0(t); }
ref T F01<T>() { T t = default; return ref F1(ref t); } // 1
ref T F02<T>() { T t = default; return ref F2(in t); } // 2
ref T F03<T>() { T t = default; return ref F2(t); } // 3
ref T F04<T>() { T t = default; return ref F3(out t); }
ref T F10<T>(ref T t) { return ref F0(t); }
ref T F11<T>(ref T t) { return ref F1(ref t); }
ref T F12<T>(ref T t) { return ref F2(in t); }
ref T F13<T>(ref T t) { return ref F2(t); }
ref T F14<T>(ref T t) { return ref F3(out t); }
ref T F20<T>(in T t) { return ref F0(t); }
ref T F22<T>(in T t) { return ref F2(in t); }
ref T F23<T>(in T t) { return ref F2(t); }
ref T F30<T>(out T t) { t = default; return ref F0(t); }
ref T F31<T>(out T t) { t = default; return ref F1(ref t); } // 4
ref T F32<T>(out T t) { t = default; return ref F2(in t); } // 5
ref T F33<T>(out T t) { t = default; return ref F2(t); } // 6
ref T F34<T>(out T t) { t = default; return ref F3(out t); }
}";
var expectedLegacyDiagnostics = new DiagnosticDescription[]
{
// (9,48): error CS8347: Cannot use a result of 'C.F1<T>(ref T)' in this context because it may expose variables referenced by parameter 't' outside of their declaration scope
// ref T F01<T>() { T t = default; return ref F1(ref t); } // 1
Diagnostic(ErrorCode.ERR_EscapeCall, "F1(ref t)").WithArguments("C.F1<T>(ref T)", "t").WithLocation(9, 48),
// (9,55): error CS8168: Cannot return local 't' by reference because it is not a ref local
// ref T F01<T>() { T t = default; return ref F1(ref t); } // 1
Diagnostic(ErrorCode.ERR_RefReturnLocal, "t").WithArguments("t").WithLocation(9, 55),
// (10,48): error CS8347: Cannot use a result of 'C.F2<T>(in T)' in this context because it may expose variables referenced by parameter 't' outside of their declaration scope
// ref T F02<T>() { T t = default; return ref F2(in t); } // 2
Diagnostic(ErrorCode.ERR_EscapeCall, "F2(in t)").WithArguments("C.F2<T>(in T)", "t").WithLocation(10, 48),
// (10,54): error CS8168: Cannot return local 't' by reference because it is not a ref local
// ref T F02<T>() { T t = default; return ref F2(in t); } // 2
Diagnostic(ErrorCode.ERR_RefReturnLocal, "t").WithArguments("t").WithLocation(10, 54),
// (11,48): error CS8347: Cannot use a result of 'C.F2<T>(in T)' in this context because it may expose variables referenced by parameter 't' outside of their declaration scope
// ref T F03<T>() { T t = default; return ref F2(t); } // 3
Diagnostic(ErrorCode.ERR_EscapeCall, "F2(t)").WithArguments("C.F2<T>(in T)", "t").WithLocation(11, 48),
// (11,51): error CS8168: Cannot return local 't' by reference because it is not a ref local
// ref T F03<T>() { T t = default; return ref F2(t); } // 3
Diagnostic(ErrorCode.ERR_RefReturnLocal, "t").WithArguments("t").WithLocation(11, 51),
// (12,48): error CS8347: Cannot use a result of 'C.F3<T>(out T)' in this context because it may expose variables referenced by parameter 't' outside of their declaration scope
// ref T F04<T>() { T t = default; return ref F3(out t); }
Diagnostic(ErrorCode.ERR_EscapeCall, "F3(out t)").WithArguments("C.F3<T>(out T)", "t").WithLocation(12, 48),
// (12,55): error CS8168: Cannot return local 't' by reference because it is not a ref local
// ref T F04<T>() { T t = default; return ref F3(out t); }
Diagnostic(ErrorCode.ERR_RefReturnLocal, "t").WithArguments("t").WithLocation(12, 55)
};
var expectedUpdatedDiagnostics = new DiagnosticDescription[]
{
// (9,48): error CS8347: Cannot use a result of 'C.F1<T>(ref T)' in this context because it may expose variables referenced by parameter 't' outside of their declaration scope
// ref T F01<T>() { T t = default; return ref F1(ref t); } // 1
Diagnostic(ErrorCode.ERR_EscapeCall, "F1(ref t)").WithArguments("C.F1<T>(ref T)", "t").WithLocation(9, 48),
// (9,55): error CS8168: Cannot return local 't' by reference because it is not a ref local
// ref T F01<T>() { T t = default; return ref F1(ref t); } // 1
Diagnostic(ErrorCode.ERR_RefReturnLocal, "t").WithArguments("t").WithLocation(9, 55),
// (10,48): error CS8347: Cannot use a result of 'C.F2<T>(in T)' in this context because it may expose variables referenced by parameter 't' outside of their declaration scope
// ref T F02<T>() { T t = default; return ref F2(in t); } // 2
Diagnostic(ErrorCode.ERR_EscapeCall, "F2(in t)").WithArguments("C.F2<T>(in T)", "t").WithLocation(10, 48),
// (10,54): error CS8168: Cannot return local 't' by reference because it is not a ref local
// ref T F02<T>() { T t = default; return ref F2(in t); } // 2
Diagnostic(ErrorCode.ERR_RefReturnLocal, "t").WithArguments("t").WithLocation(10, 54),
// (11,48): error CS8347: Cannot use a result of 'C.F2<T>(in T)' in this context because it may expose variables referenced by parameter 't' outside of their declaration scope
// ref T F03<T>() { T t = default; return ref F2(t); } // 3
Diagnostic(ErrorCode.ERR_EscapeCall, "F2(t)").WithArguments("C.F2<T>(in T)", "t").WithLocation(11, 48),
// (11,51): error CS8168: Cannot return local 't' by reference because it is not a ref local
// ref T F03<T>() { T t = default; return ref F2(t); } // 3
Diagnostic(ErrorCode.ERR_RefReturnLocal, "t").WithArguments("t").WithLocation(11, 51),
// (22,53): error CS8347: Cannot use a result of 'C.F1<T>(ref T)' in this context because it may expose variables referenced by parameter 't' outside of their declaration scope
// ref T F31<T>(out T t) { t = default; return ref F1(ref t); } // 4
Diagnostic(ErrorCode.ERR_EscapeCall, "F1(ref t)").WithArguments("C.F1<T>(ref T)", "t").WithLocation(22, 53),
// (22,60): error CS9075: Cannot return a parameter by reference 't' because it is scoped to the current method
// ref T F31<T>(out T t) { t = default; return ref F1(ref t); } // 4
Diagnostic(ErrorCode.ERR_RefReturnScopedParameter, "t").WithArguments("t").WithLocation(22, 60),
// (23,53): error CS8347: Cannot use a result of 'C.F2<T>(in T)' in this context because it may expose variables referenced by parameter 't' outside of their declaration scope
// ref T F32<T>(out T t) { t = default; return ref F2(in t); } // 5
Diagnostic(ErrorCode.ERR_EscapeCall, "F2(in t)").WithArguments("C.F2<T>(in T)", "t").WithLocation(23, 53),
// (23,59): error CS9075: Cannot return a parameter by reference 't' because it is scoped to the current method
// ref T F32<T>(out T t) { t = default; return ref F2(in t); } // 5
Diagnostic(ErrorCode.ERR_RefReturnScopedParameter, "t").WithArguments("t").WithLocation(23, 59),
// (24,53): error CS8347: Cannot use a result of 'C.F2<T>(in T)' in this context because it may expose variables referenced by parameter 't' outside of their declaration scope
// ref T F33<T>(out T t) { t = default; return ref F2(t); } // 6
Diagnostic(ErrorCode.ERR_EscapeCall, "F2(t)").WithArguments("C.F2<T>(in T)", "t").WithLocation(24, 53),
// (24,56): error CS9075: Cannot return a parameter by reference 't' because it is scoped to the current method
// ref T F33<T>(out T t) { t = default; return ref F2(t); } // 6
Diagnostic(ErrorCode.ERR_RefReturnScopedParameter, "t").WithArguments("t").WithLocation(24, 56)
};
var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10);
comp.VerifyDiagnostics(comp.Assembly.RuntimeSupportsByRefFields ? expectedUpdatedDiagnostics : expectedLegacyDiagnostics);
comp = CreateCompilation(source);
comp.VerifyEmitDiagnostics(expectedUpdatedDiagnostics);
}
[Fact]
public void MethodInvocation_Lvalue_03()
{
var source =
@"class Program
{
static ref T F0<T, U>(T t, U u) => throw null;
static ref T F1<T, U>(T t, ref U u) => throw null;
static ref T F2<T, U>(T t, in U u) => throw null;
static ref T F3<T, U>(T t, out U u) => throw null;
static ref T F4<T, U>(ref T t, ref U u) => throw null;
static ref T F5<T, U>(ref T t, in U u) => throw null;
static ref T F6<T, U>(ref T t, out U u) => throw null;
static ref T F7<T, U>(in T t, in U u) => throw null;
static ref T F8<T, U>(in T t, out U u) => throw null;
static ref T F9<T, U>(out T t, out U u) => throw null;
static ref T G0<T, U>()
{
T t = default;
U u = default;
return ref F0(t, u);
}
static ref T G1<T, U>()
{
T t = default;
U u = default;
return ref F1(t, ref u); // 1
}
static ref T G2A<T, U>()
{
T t = default;
U u = default;
return ref F2(t, in u); // 2
}
static ref T G2B<T, U>()
{
T t = default;
U u = default;
return ref F2(t, u); // 3
}
static ref T G3<T, U>()
{
T t = default;
U u = default;
return ref F3(t, out u); // *
}
static ref T G4<T, U>()
{
T t = default;
U u = default;
return ref F4(ref t, ref u); // 4
}
static ref T G5A<T, U>()
{
T t = default;
U u = default;
return ref F5(ref t, in u); // 5
}
static ref T G5B<T, U>()
{
T t = default;
U u = default;
return ref F5(ref t, u); // 6
}
static ref T G6<T, U>()
{
T t = default;
U u = default;
return ref F6(ref t, out u); // 7
}
static ref T G7A<T, U>()
{
T t = default;
U u = default;
return ref F7(in t, in u); // 8
}
static ref T G7B<T, U>()
{
T t = default;
U u = default;
return ref F7(t, u); // 9
}
static ref T G8A<T, U>()
{
T t = default;
U u = default;
return ref F8(in t, out u); // 10
}
static ref T G8B<T, U>()
{
T t = default;
U u = default;
return ref F8(t, out u); // 11
}
static ref T G9<T, U>()
{
T t = default;
U u = default;
return ref F9(out t, out u); // *
}
}";
var expectedLegacyDiagnostics = new DiagnosticDescription[]
{
// (23,20): error CS8347: Cannot use a result of 'Program.F1<T, U>(T, ref U)' in this context because it may expose variables referenced by parameter 'u' outside of their declaration scope
// return ref F1(t, ref u); // 1
Diagnostic(ErrorCode.ERR_EscapeCall, "F1(t, ref u)").WithArguments("Program.F1<T, U>(T, ref U)", "u").WithLocation(23, 20),
// (23,30): error CS8168: Cannot return local 'u' by reference because it is not a ref local
// return ref F1(t, ref u); // 1
Diagnostic(ErrorCode.ERR_RefReturnLocal, "u").WithArguments("u").WithLocation(23, 30),
// (29,20): error CS8347: Cannot use a result of 'Program.F2<T, U>(T, in U)' in this context because it may expose variables referenced by parameter 'u' outside of their declaration scope
// return ref F2(t, in u); // 2
Diagnostic(ErrorCode.ERR_EscapeCall, "F2(t, in u)").WithArguments("Program.F2<T, U>(T, in U)", "u").WithLocation(29, 20),
// (29,29): error CS8168: Cannot return local 'u' by reference because it is not a ref local
// return ref F2(t, in u); // 2
Diagnostic(ErrorCode.ERR_RefReturnLocal, "u").WithArguments("u").WithLocation(29, 29),
// (35,20): error CS8347: Cannot use a result of 'Program.F2<T, U>(T, in U)' in this context because it may expose variables referenced by parameter 'u' outside of their declaration scope
// return ref F2(t, u); // 3
Diagnostic(ErrorCode.ERR_EscapeCall, "F2(t, u)").WithArguments("Program.F2<T, U>(T, in U)", "u").WithLocation(35, 20),
// (35,26): error CS8168: Cannot return local 'u' by reference because it is not a ref local
// return ref F2(t, u); // 3
Diagnostic(ErrorCode.ERR_RefReturnLocal, "u").WithArguments("u").WithLocation(35, 26),
// (41,20): error CS8347: Cannot use a result of 'Program.F3<T, U>(T, out U)' in this context because it may expose variables referenced by parameter 'u' outside of their declaration scope
// return ref F3(t, out u); // *
Diagnostic(ErrorCode.ERR_EscapeCall, "F3(t, out u)").WithArguments("Program.F3<T, U>(T, out U)", "u").WithLocation(41, 20),
// (41,30): error CS8168: Cannot return local 'u' by reference because it is not a ref local
// return ref F3(t, out u); // *
Diagnostic(ErrorCode.ERR_RefReturnLocal, "u").WithArguments("u").WithLocation(41, 30),
// (47,20): error CS8347: Cannot use a result of 'Program.F4<T, U>(ref T, ref U)' in this context because it may expose variables referenced by parameter 't' outside of their declaration scope
// return ref F4(ref t, ref u); // 4
Diagnostic(ErrorCode.ERR_EscapeCall, "F4(ref t, ref u)").WithArguments("Program.F4<T, U>(ref T, ref U)", "t").WithLocation(47, 20),
// (47,27): error CS8168: Cannot return local 't' by reference because it is not a ref local
// return ref F4(ref t, ref u); // 4
Diagnostic(ErrorCode.ERR_RefReturnLocal, "t").WithArguments("t").WithLocation(47, 27),
// (53,20): error CS8347: Cannot use a result of 'Program.F5<T, U>(ref T, in U)' in this context because it may expose variables referenced by parameter 't' outside of their declaration scope
// return ref F5(ref t, in u); // 5
Diagnostic(ErrorCode.ERR_EscapeCall, "F5(ref t, in u)").WithArguments("Program.F5<T, U>(ref T, in U)", "t").WithLocation(53, 20),
// (53,27): error CS8168: Cannot return local 't' by reference because it is not a ref local
// return ref F5(ref t, in u); // 5
Diagnostic(ErrorCode.ERR_RefReturnLocal, "t").WithArguments("t").WithLocation(53, 27),
// (59,20): error CS8347: Cannot use a result of 'Program.F5<T, U>(ref T, in U)' in this context because it may expose variables referenced by parameter 't' outside of their declaration scope
// return ref F5(ref t, u); // 6
Diagnostic(ErrorCode.ERR_EscapeCall, "F5(ref t, u)").WithArguments("Program.F5<T, U>(ref T, in U)", "t").WithLocation(59, 20),
// (59,27): error CS8168: Cannot return local 't' by reference because it is not a ref local
// return ref F5(ref t, u); // 6
Diagnostic(ErrorCode.ERR_RefReturnLocal, "t").WithArguments("t").WithLocation(59, 27),
// (65,20): error CS8347: Cannot use a result of 'Program.F6<T, U>(ref T, out U)' in this context because it may expose variables referenced by parameter 't' outside of their declaration scope
// return ref F6(ref t, out u); // 7
Diagnostic(ErrorCode.ERR_EscapeCall, "F6(ref t, out u)").WithArguments("Program.F6<T, U>(ref T, out U)", "t").WithLocation(65, 20),
// (65,27): error CS8168: Cannot return local 't' by reference because it is not a ref local
// return ref F6(ref t, out u); // 7
Diagnostic(ErrorCode.ERR_RefReturnLocal, "t").WithArguments("t").WithLocation(65, 27),
// (71,20): error CS8347: Cannot use a result of 'Program.F7<T, U>(in T, in U)' in this context because it may expose variables referenced by parameter 't' outside of their declaration scope
// return ref F7(in t, in u); // 8
Diagnostic(ErrorCode.ERR_EscapeCall, "F7(in t, in u)").WithArguments("Program.F7<T, U>(in T, in U)", "t").WithLocation(71, 20),
// (71,26): error CS8168: Cannot return local 't' by reference because it is not a ref local
// return ref F7(in t, in u); // 8
Diagnostic(ErrorCode.ERR_RefReturnLocal, "t").WithArguments("t").WithLocation(71, 26),
// (77,20): error CS8347: Cannot use a result of 'Program.F7<T, U>(in T, in U)' in this context because it may expose variables referenced by parameter 't' outside of their declaration scope
// return ref F7(t, u); // 9
Diagnostic(ErrorCode.ERR_EscapeCall, "F7(t, u)").WithArguments("Program.F7<T, U>(in T, in U)", "t").WithLocation(77, 20),
// (77,23): error CS8168: Cannot return local 't' by reference because it is not a ref local
// return ref F7(t, u); // 9
Diagnostic(ErrorCode.ERR_RefReturnLocal, "t").WithArguments("t").WithLocation(77, 23),
// (83,20): error CS8347: Cannot use a result of 'Program.F8<T, U>(in T, out U)' in this context because it may expose variables referenced by parameter 't' outside of their declaration scope
// return ref F8(in t, out u); // 10
Diagnostic(ErrorCode.ERR_EscapeCall, "F8(in t, out u)").WithArguments("Program.F8<T, U>(in T, out U)", "t").WithLocation(83, 20),
// (83,26): error CS8168: Cannot return local 't' by reference because it is not a ref local
// return ref F8(in t, out u); // 10
Diagnostic(ErrorCode.ERR_RefReturnLocal, "t").WithArguments("t").WithLocation(83, 26),
// (89,20): error CS8347: Cannot use a result of 'Program.F8<T, U>(in T, out U)' in this context because it may expose variables referenced by parameter 't' outside of their declaration scope
// return ref F8(t, out u); // 11
Diagnostic(ErrorCode.ERR_EscapeCall, "F8(t, out u)").WithArguments("Program.F8<T, U>(in T, out U)", "t").WithLocation(89, 20),
// (89,23): error CS8168: Cannot return local 't' by reference because it is not a ref local
// return ref F8(t, out u); // 11
Diagnostic(ErrorCode.ERR_RefReturnLocal, "t").WithArguments("t").WithLocation(89, 23),
// (95,20): error CS8347: Cannot use a result of 'Program.F9<T, U>(out T, out U)' in this context because it may expose variables referenced by parameter 't' outside of their declaration scope
// return ref F9(out t, out u); // *
Diagnostic(ErrorCode.ERR_EscapeCall, "F9(out t, out u)").WithArguments("Program.F9<T, U>(out T, out U)", "t").WithLocation(95, 20),
// (95,27): error CS8168: Cannot return local 't' by reference because it is not a ref local
// return ref F9(out t, out u); // *
Diagnostic(ErrorCode.ERR_RefReturnLocal, "t").WithArguments("t").WithLocation(95, 27)
};
var expectedUpdatedDiagnostics = new DiagnosticDescription[]
{
// (23,20): error CS8347: Cannot use a result of 'Program.F1<T, U>(T, ref U)' in this context because it may expose variables referenced by parameter 'u' outside of their declaration scope
// return ref F1(t, ref u); // 1
Diagnostic(ErrorCode.ERR_EscapeCall, "F1(t, ref u)").WithArguments("Program.F1<T, U>(T, ref U)", "u").WithLocation(23, 20),
// (23,30): error CS8168: Cannot return local 'u' by reference because it is not a ref local
// return ref F1(t, ref u); // 1
Diagnostic(ErrorCode.ERR_RefReturnLocal, "u").WithArguments("u").WithLocation(23, 30),
// (29,20): error CS8347: Cannot use a result of 'Program.F2<T, U>(T, in U)' in this context because it may expose variables referenced by parameter 'u' outside of their declaration scope
// return ref F2(t, in u); // 2
Diagnostic(ErrorCode.ERR_EscapeCall, "F2(t, in u)").WithArguments("Program.F2<T, U>(T, in U)", "u").WithLocation(29, 20),
// (29,29): error CS8168: Cannot return local 'u' by reference because it is not a ref local
// return ref F2(t, in u); // 2
Diagnostic(ErrorCode.ERR_RefReturnLocal, "u").WithArguments("u").WithLocation(29, 29),
// (35,20): error CS8347: Cannot use a result of 'Program.F2<T, U>(T, in U)' in this context because it may expose variables referenced by parameter 'u' outside of their declaration scope
// return ref F2(t, u); // 3
Diagnostic(ErrorCode.ERR_EscapeCall, "F2(t, u)").WithArguments("Program.F2<T, U>(T, in U)", "u").WithLocation(35, 20),
// (35,26): error CS8168: Cannot return local 'u' by reference because it is not a ref local
// return ref F2(t, u); // 3
Diagnostic(ErrorCode.ERR_RefReturnLocal, "u").WithArguments("u").WithLocation(35, 26),
// (47,20): error CS8347: Cannot use a result of 'Program.F4<T, U>(ref T, ref U)' in this context because it may expose variables referenced by parameter 't' outside of their declaration scope
// return ref F4(ref t, ref u); // 4
Diagnostic(ErrorCode.ERR_EscapeCall, "F4(ref t, ref u)").WithArguments("Program.F4<T, U>(ref T, ref U)", "t").WithLocation(47, 20),
// (47,27): error CS8168: Cannot return local 't' by reference because it is not a ref local
// return ref F4(ref t, ref u); // 4
Diagnostic(ErrorCode.ERR_RefReturnLocal, "t").WithArguments("t").WithLocation(47, 27),
// (53,20): error CS8347: Cannot use a result of 'Program.F5<T, U>(ref T, in U)' in this context because it may expose variables referenced by parameter 't' outside of their declaration scope
// return ref F5(ref t, in u); // 5
Diagnostic(ErrorCode.ERR_EscapeCall, "F5(ref t, in u)").WithArguments("Program.F5<T, U>(ref T, in U)", "t").WithLocation(53, 20),
// (53,27): error CS8168: Cannot return local 't' by reference because it is not a ref local
// return ref F5(ref t, in u); // 5
Diagnostic(ErrorCode.ERR_RefReturnLocal, "t").WithArguments("t").WithLocation(53, 27),
// (59,20): error CS8347: Cannot use a result of 'Program.F5<T, U>(ref T, in U)' in this context because it may expose variables referenced by parameter 't' outside of their declaration scope
// return ref F5(ref t, u); // 6
Diagnostic(ErrorCode.ERR_EscapeCall, "F5(ref t, u)").WithArguments("Program.F5<T, U>(ref T, in U)", "t").WithLocation(59, 20),
// (59,27): error CS8168: Cannot return local 't' by reference because it is not a ref local
// return ref F5(ref t, u); // 6
Diagnostic(ErrorCode.ERR_RefReturnLocal, "t").WithArguments("t").WithLocation(59, 27),
// (65,20): error CS8347: Cannot use a result of 'Program.F6<T, U>(ref T, out U)' in this context because it may expose variables referenced by parameter 't' outside of their declaration scope
// return ref F6(ref t, out u); // 7
Diagnostic(ErrorCode.ERR_EscapeCall, "F6(ref t, out u)").WithArguments("Program.F6<T, U>(ref T, out U)", "t").WithLocation(65, 20),
// (65,27): error CS8168: Cannot return local 't' by reference because it is not a ref local
// return ref F6(ref t, out u); // 7
Diagnostic(ErrorCode.ERR_RefReturnLocal, "t").WithArguments("t").WithLocation(65, 27),
// (71,20): error CS8347: Cannot use a result of 'Program.F7<T, U>(in T, in U)' in this context because it may expose variables referenced by parameter 't' outside of their declaration scope
// return ref F7(in t, in u); // 8
Diagnostic(ErrorCode.ERR_EscapeCall, "F7(in t, in u)").WithArguments("Program.F7<T, U>(in T, in U)", "t").WithLocation(71, 20),
// (71,26): error CS8168: Cannot return local 't' by reference because it is not a ref local
// return ref F7(in t, in u); // 8
Diagnostic(ErrorCode.ERR_RefReturnLocal, "t").WithArguments("t").WithLocation(71, 26),
// (77,20): error CS8347: Cannot use a result of 'Program.F7<T, U>(in T, in U)' in this context because it may expose variables referenced by parameter 't' outside of their declaration scope
// return ref F7(t, u); // 9
Diagnostic(ErrorCode.ERR_EscapeCall, "F7(t, u)").WithArguments("Program.F7<T, U>(in T, in U)", "t").WithLocation(77, 20),
// (77,23): error CS8168: Cannot return local 't' by reference because it is not a ref local
// return ref F7(t, u); // 9
Diagnostic(ErrorCode.ERR_RefReturnLocal, "t").WithArguments("t").WithLocation(77, 23),
// (83,20): error CS8347: Cannot use a result of 'Program.F8<T, U>(in T, out U)' in this context because it may expose variables referenced by parameter 't' outside of their declaration scope
// return ref F8(in t, out u); // 10
Diagnostic(ErrorCode.ERR_EscapeCall, "F8(in t, out u)").WithArguments("Program.F8<T, U>(in T, out U)", "t").WithLocation(83, 20),
// (83,26): error CS8168: Cannot return local 't' by reference because it is not a ref local
// return ref F8(in t, out u); // 10
Diagnostic(ErrorCode.ERR_RefReturnLocal, "t").WithArguments("t").WithLocation(83, 26),
// (89,20): error CS8347: Cannot use a result of 'Program.F8<T, U>(in T, out U)' in this context because it may expose variables referenced by parameter 't' outside of their declaration scope
// return ref F8(t, out u); // 11
Diagnostic(ErrorCode.ERR_EscapeCall, "F8(t, out u)").WithArguments("Program.F8<T, U>(in T, out U)", "t").WithLocation(89, 20),
// (89,23): error CS8168: Cannot return local 't' by reference because it is not a ref local
// return ref F8(t, out u); // 11
Diagnostic(ErrorCode.ERR_RefReturnLocal, "t").WithArguments("t").WithLocation(89, 23)
};
var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10);
comp.VerifyDiagnostics(comp.Assembly.RuntimeSupportsByRefFields ? expectedUpdatedDiagnostics : expectedLegacyDiagnostics);
comp = CreateCompilation(source);
comp.VerifyEmitDiagnostics(expectedUpdatedDiagnostics);
}
[Fact]
public void MethodInvocation_Rvalue_01()
{
var source =
@"struct S
{
internal T F0<T>(T t) => throw null;
internal T F1<T>(ref T t) => throw null;
internal T F2<T>(in T t) => throw null;
internal T F3<T>(out T t) => throw null;
}
class Program
{
static T F00<T>() { S s = default; T t = default; return s.F0(t); }
static T F01<T>() { S s = default; T t = default; return s.F1(ref t); }
static T F02<T>() { S s = default; T t = default; return s.F2(in t); }
static T F03<T>() { S s = default; T t = default; return s.F2(t); }
static T F04<T>() { S s = default; T t = default; return s.F3(out t); }
static T F10<T>(ref T t) { S s = default; return s.F0(t); }
static T F11<T>(ref T t) { S s = default; return s.F1(ref t); }
static T F12<T>(ref T t) { S s = default; return s.F2(in t); }
static T F13<T>(ref T t) { S s = default; return s.F2(t); }
static T F14<T>(ref T t) { S s = default; return s.F3(out t); }
static T F20<T>(in T t) { S s = default; return s.F0(t); }
static T F22<T>(in T t) { S s = default; return s.F2(in t); }
static T F23<T>(in T t) { S s = default; return s.F2(t); }
static T F30<T>(out T t) { S s = default; t = default; return s.F0(t); }
static T F31<T>(out T t) { S s = default; t = default; return s.F1(ref t); }
static T F32<T>(out T t) { S s = default; t = default; return s.F2(in t); }
static T F33<T>(out T t) { S s = default; t = default; return s.F2(t); }
static T F34<T>(out T t) { S s = default; t = default; return s.F3(out t); }
static T F41<T>(ref S s) { T t = default; return s.F0(t); }
static T F42<T>(in S s) { T t = default; return s.F1(ref t); }
static T F43<T>(out S s) { s = default; T t = default; return s.F2(in t); }
static T F51<T>(ref S s, ref T t) { return s.F0(t); }
static T F52<T>(in S s, ref T t) { return s.F1(ref t); }
static T F53<T>(out S s, ref T t) { s = default; return s.F2(in t); }
}";
var expectedLegacyDiagnostics = new DiagnosticDescription[]
{
};
var expectedUpdatedDiagnostics = new DiagnosticDescription[]
{
};
var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10);
comp.VerifyDiagnostics(comp.Assembly.RuntimeSupportsByRefFields ? expectedUpdatedDiagnostics : expectedLegacyDiagnostics);
comp = CreateCompilation(source);
comp.VerifyEmitDiagnostics(expectedUpdatedDiagnostics);
}
[Fact]
public void MethodInvocation_Rvalue_02()
{
var source =
@"class C
{
T F0<T>(T t) => throw null;
T F1<T>(ref T t) => throw null;
T F2<T>(in T t) => throw null;
T F3<T>(out T t) => throw null;
T F00<T>() { T t = default; return F0(t); }
T F01<T>() { T t = default; return F1(ref t); }
T F02<T>() { T t = default; return F2(in t); }
T F03<T>() { T t = default; return F2(t); }
T F04<T>() { T t = default; return F3(out t); }
T F10<T>(ref T t) { return F0(t); }
T F11<T>(ref T t) { return F1(ref t); }
T F12<T>(ref T t) { return F2(in t); }
T F13<T>(ref T t) { return F2(t); }
T F14<T>(ref T t) { return F3(out t); }
T F20<T>(in T t) { return F0(t); }
T F22<T>(in T t) { return F2(in t); }
T F23<T>(in T t) { return F2(t); }
T F30<T>(out T t) { t = default; return F0(t); }
T F31<T>(out T t) { t = default; return F1(ref t); }
T F32<T>(out T t) { t = default; return F2(in t); }
T F33<T>(out T t) { t = default; return F2(t); }
T F34<T>(out T t) { t = default; return F3(out t); }
}";
var expectedLegacyDiagnostics = new DiagnosticDescription[]
{
};
var expectedUpdatedDiagnostics = new DiagnosticDescription[]
{
};
var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10);
comp.VerifyDiagnostics(comp.Assembly.RuntimeSupportsByRefFields ? expectedUpdatedDiagnostics : expectedLegacyDiagnostics);
comp = CreateCompilation(source);
comp.VerifyEmitDiagnostics(expectedUpdatedDiagnostics);
}
[Fact]
public void MethodInvocation_Rvalue_03()
{
var source =
@"class Program
{
static T F0<T, U>(T t, U u) => throw null;
static T F1<T, U>(T t, ref U u) => throw null;
static T F2<T, U>(T t, in U u) => throw null;
static T F3<T, U>(T t, out U u) => throw null;
static T F4<T, U>(ref T t, ref U u) => throw null;
static T F5<T, U>(ref T t, in U u) => throw null;
static T F6<T, U>(ref T t, out U u) => throw null;
static T F7<T, U>(in T t, in U u) => throw null;
static T F8<T, U>(in T t, out U u) => throw null;
static T F9<T, U>(out T t, out U u) => throw null;
static T G0<T, U>()
{
T t = default;
U u = default;
return F0(t, u);
}
static T G1<T, U>()
{
T t = default;
U u = default;
return F1(t, ref u);
}
static T G2A<T, U>()
{
T t = default;
U u = default;
return F2(t, in u);
}
static T G2B<T, U>()
{
T t = default;
U u = default;
return F2(t, u);
}
static T G3<T, U>()
{
T t = default;
U u = default;
return F3(t, out u);
}
static T G4<T, U>()
{
T t = default;
U u = default;
return F4(ref t, ref u);
}
static T G5A<T, U>()
{
T t = default;
U u = default;
return F5(ref t, in u);
}
static T G5B<T, U>()
{
T t = default;
U u = default;
return F5(ref t, u);
}
static T G6<T, U>()
{
T t = default;
U u = default;
return F6(ref t, out u);
}
static T G7A<T, U>()
{
T t = default;
U u = default;
return F7(in t, in u);
}
static T G7B<T, U>()
{
T t = default;
U u = default;
return F7(t, u);
}
static T G8A<T, U>()
{
T t = default;
U u = default;
return F8(in t, out u);
}
static T G8B<T, U>()
{
T t = default;
U u = default;
return F8(t, out u);
}
static T G9<T, U>()
{
T t = default;
U u = default;
return F9(out t, out u);
}
}";
var expectedLegacyDiagnostics = new DiagnosticDescription[]
{
};
var expectedUpdatedDiagnostics = new DiagnosticDescription[]
{
};
var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10);
comp.VerifyDiagnostics(comp.Assembly.RuntimeSupportsByRefFields ? expectedUpdatedDiagnostics : expectedLegacyDiagnostics);
comp = CreateCompilation(source);
comp.VerifyEmitDiagnostics(expectedUpdatedDiagnostics);
}
[Fact]
public void MethodInvocation_Rvalue_04()
{
var source =
@"ref struct R<T>
{
}
struct S
{
internal R<T> F0<T>(T t) => throw null;
internal R<T> F1<T>(ref T t) => throw null;
internal R<T> F2<T>(in T t) => throw null;
internal R<T> F3<T>(out T t) => throw null;
}
class Program
{
static R<T> F00<T>() { S s = default; T t = default; return s.F0(t); }
static R<T> F01<T>() { S s = default; T t = default; return s.F1(ref t); } // 1
static R<T> F02<T>() { S s = default; T t = default; return s.F2(in t); } // 2
static R<T> F03<T>() { S s = default; T t = default; return s.F2(t); } // 3
static R<T> F04<T>() { S s = default; T t = default; return s.F3(out t); }
static R<T> F10<T>(ref T t) { S s = default; return s.F0(t); }
static R<T> F11<T>(ref T t) { S s = default; return s.F1(ref t); }
static R<T> F12<T>(ref T t) { S s = default; return s.F2(in t); }
static R<T> F13<T>(ref T t) { S s = default; return s.F2(t); }
static R<T> F14<T>(ref T t) { S s = default; return s.F3(out t); }
static R<T> F20<T>(in T t) { S s = default; return s.F0(t); }
static R<T> F22<T>(in T t) { S s = default; return s.F2(in t); }
static R<T> F23<T>(in T t) { S s = default; return s.F2(t); }
static R<T> F30<T>(out T t) { S s = default; t = default; return s.F0(t); }
static R<T> F31<T>(out T t) { S s = default; t = default; return s.F1(ref t); } // 4
static R<T> F32<T>(out T t) { S s = default; t = default; return s.F2(in t); } // 5
static R<T> F33<T>(out T t) { S s = default; t = default; return s.F2(t); } // 6
static R<T> F34<T>(out T t) { S s = default; t = default; return s.F3(out t); }
static R<T> F40<T>(ref S s) { T t = default; return s.F0(t); }
static R<T> F41<T>(in S s) { T t = default; return s.F1(ref t); } // 7
static R<T> F42<T>(out S s) { s = default; T t = default; return s.F2(in t); } // 8
static R<T> F43<T>(out S s) { s = default; T t = default; return s.F2(t); } // 9
static R<T> F44<T>(out S s) { s = default; T t = default; return s.F3(out t); }
static R<T> F50<T>(ref S s, ref T t) { return s.F0(t); }
static R<T> F51<T>(in S s, ref T t) { return s.F1(ref t); }
static R<T> F52<T>(out S s, ref T t) { s = default; return s.F2(in t); }
static R<T> F53<T>(out S s, ref T t) { s = default; return s.F2(t); }
static R<T> F54<T>(out S s, ref T t) { s = default; return s.F3(out t); }
}";
var expectedLegacyDiagnostics = new DiagnosticDescription[]
{
};
var expectedUpdatedDiagnostics = new DiagnosticDescription[]
{
// (14,65): error CS8347: Cannot use a result of 'S.F1<T>(ref T)' in this context because it may expose variables referenced by parameter 't' outside of their declaration scope
// static R<T> F01<T>() { S s = default; T t = default; return s.F1(ref t); } // 1
Diagnostic(ErrorCode.ERR_EscapeCall, "s.F1(ref t)").WithArguments("S.F1<T>(ref T)", "t").WithLocation(14, 65),
// (14,74): error CS8168: Cannot return local 't' by reference because it is not a ref local
// static R<T> F01<T>() { S s = default; T t = default; return s.F1(ref t); } // 1
Diagnostic(ErrorCode.ERR_RefReturnLocal, "t").WithArguments("t").WithLocation(14, 74),
// (15,65): error CS8347: Cannot use a result of 'S.F2<T>(in T)' in this context because it may expose variables referenced by parameter 't' outside of their declaration scope
// static R<T> F02<T>() { S s = default; T t = default; return s.F2(in t); } // 2
Diagnostic(ErrorCode.ERR_EscapeCall, "s.F2(in t)").WithArguments("S.F2<T>(in T)", "t").WithLocation(15, 65),
// (15,73): error CS8168: Cannot return local 't' by reference because it is not a ref local
// static R<T> F02<T>() { S s = default; T t = default; return s.F2(in t); } // 2
Diagnostic(ErrorCode.ERR_RefReturnLocal, "t").WithArguments("t").WithLocation(15, 73),
// (16,65): error CS8347: Cannot use a result of 'S.F2<T>(in T)' in this context because it may expose variables referenced by parameter 't' outside of their declaration scope
// static R<T> F03<T>() { S s = default; T t = default; return s.F2(t); } // 3
Diagnostic(ErrorCode.ERR_EscapeCall, "s.F2(t)").WithArguments("S.F2<T>(in T)", "t").WithLocation(16, 65),
// (16,70): error CS8168: Cannot return local 't' by reference because it is not a ref local
// static R<T> F03<T>() { S s = default; T t = default; return s.F2(t); } // 3
Diagnostic(ErrorCode.ERR_RefReturnLocal, "t").WithArguments("t").WithLocation(16, 70),
// (27,70): error CS8347: Cannot use a result of 'S.F1<T>(ref T)' in this context because it may expose variables referenced by parameter 't' outside of their declaration scope
// static R<T> F31<T>(out T t) { S s = default; t = default; return s.F1(ref t); } // 4
Diagnostic(ErrorCode.ERR_EscapeCall, "s.F1(ref t)").WithArguments("S.F1<T>(ref T)", "t").WithLocation(27, 70),
// (27,79): error CS9075: Cannot return a parameter by reference 't' because it is scoped to the current method
// static R<T> F31<T>(out T t) { S s = default; t = default; return s.F1(ref t); } // 4
Diagnostic(ErrorCode.ERR_RefReturnScopedParameter, "t").WithArguments("t").WithLocation(27, 79),
// (28,70): error CS8347: Cannot use a result of 'S.F2<T>(in T)' in this context because it may expose variables referenced by parameter 't' outside of their declaration scope
// static R<T> F32<T>(out T t) { S s = default; t = default; return s.F2(in t); } // 5
Diagnostic(ErrorCode.ERR_EscapeCall, "s.F2(in t)").WithArguments("S.F2<T>(in T)", "t").WithLocation(28, 70),
// (28,78): error CS9075: Cannot return a parameter by reference 't' because it is scoped to the current method
// static R<T> F32<T>(out T t) { S s = default; t = default; return s.F2(in t); } // 5
Diagnostic(ErrorCode.ERR_RefReturnScopedParameter, "t").WithArguments("t").WithLocation(28, 78),
// (29,70): error CS8347: Cannot use a result of 'S.F2<T>(in T)' in this context because it may expose variables referenced by parameter 't' outside of their declaration scope
// static R<T> F33<T>(out T t) { S s = default; t = default; return s.F2(t); } // 6
Diagnostic(ErrorCode.ERR_EscapeCall, "s.F2(t)").WithArguments("S.F2<T>(in T)", "t").WithLocation(29, 70),
// (29,75): error CS9075: Cannot return a parameter by reference 't' because it is scoped to the current method
// static R<T> F33<T>(out T t) { S s = default; t = default; return s.F2(t); } // 6
Diagnostic(ErrorCode.ERR_RefReturnScopedParameter, "t").WithArguments("t").WithLocation(29, 75),
// (32,56): error CS8347: Cannot use a result of 'S.F1<T>(ref T)' in this context because it may expose variables referenced by parameter 't' outside of their declaration scope
// static R<T> F41<T>(in S s) { T t = default; return s.F1(ref t); } // 7
Diagnostic(ErrorCode.ERR_EscapeCall, "s.F1(ref t)").WithArguments("S.F1<T>(ref T)", "t").WithLocation(32, 56),
// (32,65): error CS8168: Cannot return local 't' by reference because it is not a ref local
// static R<T> F41<T>(in S s) { T t = default; return s.F1(ref t); } // 7
Diagnostic(ErrorCode.ERR_RefReturnLocal, "t").WithArguments("t").WithLocation(32, 65),
// (33,70): error CS8347: Cannot use a result of 'S.F2<T>(in T)' in this context because it may expose variables referenced by parameter 't' outside of their declaration scope
// static R<T> F42<T>(out S s) { s = default; T t = default; return s.F2(in t); } // 8
Diagnostic(ErrorCode.ERR_EscapeCall, "s.F2(in t)").WithArguments("S.F2<T>(in T)", "t").WithLocation(33, 70),
// (33,78): error CS8168: Cannot return local 't' by reference because it is not a ref local
// static R<T> F42<T>(out S s) { s = default; T t = default; return s.F2(in t); } // 8
Diagnostic(ErrorCode.ERR_RefReturnLocal, "t").WithArguments("t").WithLocation(33, 78),
// (34,70): error CS8347: Cannot use a result of 'S.F2<T>(in T)' in this context because it may expose variables referenced by parameter 't' outside of their declaration scope
// static R<T> F43<T>(out S s) { s = default; T t = default; return s.F2(t); } // 9
Diagnostic(ErrorCode.ERR_EscapeCall, "s.F2(t)").WithArguments("S.F2<T>(in T)", "t").WithLocation(34, 70),
// (34,75): error CS8168: Cannot return local 't' by reference because it is not a ref local
// static R<T> F43<T>(out S s) { s = default; T t = default; return s.F2(t); } // 9
Diagnostic(ErrorCode.ERR_RefReturnLocal, "t").WithArguments("t").WithLocation(34, 75)
};
var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10);
comp.VerifyDiagnostics(comp.Assembly.RuntimeSupportsByRefFields ? expectedUpdatedDiagnostics : expectedLegacyDiagnostics);
comp = CreateCompilation(source);
comp.VerifyEmitDiagnostics(expectedUpdatedDiagnostics);
}
[Fact]
public void MethodInvocation_Rvalue_05()
{
var source =
@"ref struct R
{
}
class C
{
R F0<T>(T t) => throw null;
R F1<T>(ref T t) => throw null;
R F2<T>(in T t) => throw null;
R F3<T>(out T t) => throw null;
R F00<T>() { T t = default; return F0(t); }
R F01<T>() { T t = default; return F1(ref t); } // 1
R F02<T>() { T t = default; return F2(in t); } // 2
R F03<T>() { T t = default; return F2(t); } // 3
R F04<T>() { T t = default; return F3(out t); }
R F10<T>(ref T t) { return F0(t); }
R F11<T>(ref T t) { return F1(ref t); }
R F12<T>(ref T t) { return F2(in t); }
R F13<T>(ref T t) { return F2(t); }
R F14<T>(ref T t) { return F3(out t); }
R F20<T>(in T t) { return F0(t); }
R F22<T>(in T t) { return F2(in t); }
R F23<T>(in T t) { return F2(t); }
R F30<T>(out T t) { t = default; return F0(t); }
R F31<T>(out T t) { t = default; return F1(ref t); } // 4
R F32<T>(out T t) { t = default; return F2(in t); } // 5
R F33<T>(out T t) { t = default; return F2(t); } // 6
R F34<T>(out T t) { t = default; return F3(out t); }
}";
var expectedLegacyDiagnostics = new DiagnosticDescription[]
{
};
var expectedUpdatedDiagnostics = new DiagnosticDescription[]
{
// (12,40): error CS8347: Cannot use a result of 'C.F1<T>(ref T)' in this context because it may expose variables referenced by parameter 't' outside of their declaration scope
// R F01<T>() { T t = default; return F1(ref t); } // 1
Diagnostic(ErrorCode.ERR_EscapeCall, "F1(ref t)").WithArguments("C.F1<T>(ref T)", "t").WithLocation(12, 40),
// (12,47): error CS8168: Cannot return local 't' by reference because it is not a ref local
// R F01<T>() { T t = default; return F1(ref t); } // 1
Diagnostic(ErrorCode.ERR_RefReturnLocal, "t").WithArguments("t").WithLocation(12, 47),
// (13,40): error CS8347: Cannot use a result of 'C.F2<T>(in T)' in this context because it may expose variables referenced by parameter 't' outside of their declaration scope
// R F02<T>() { T t = default; return F2(in t); } // 2
Diagnostic(ErrorCode.ERR_EscapeCall, "F2(in t)").WithArguments("C.F2<T>(in T)", "t").WithLocation(13, 40),
// (13,46): error CS8168: Cannot return local 't' by reference because it is not a ref local
// R F02<T>() { T t = default; return F2(in t); } // 2
Diagnostic(ErrorCode.ERR_RefReturnLocal, "t").WithArguments("t").WithLocation(13, 46),
// (14,40): error CS8347: Cannot use a result of 'C.F2<T>(in T)' in this context because it may expose variables referenced by parameter 't' outside of their declaration scope
// R F03<T>() { T t = default; return F2(t); } // 3
Diagnostic(ErrorCode.ERR_EscapeCall, "F2(t)").WithArguments("C.F2<T>(in T)", "t").WithLocation(14, 40),
// (14,43): error CS8168: Cannot return local 't' by reference because it is not a ref local
// R F03<T>() { T t = default; return F2(t); } // 3
Diagnostic(ErrorCode.ERR_RefReturnLocal, "t").WithArguments("t").WithLocation(14, 43),
// (25,45): error CS8347: Cannot use a result of 'C.F1<T>(ref T)' in this context because it may expose variables referenced by parameter 't' outside of their declaration scope
// R F31<T>(out T t) { t = default; return F1(ref t); } // 4
Diagnostic(ErrorCode.ERR_EscapeCall, "F1(ref t)").WithArguments("C.F1<T>(ref T)", "t").WithLocation(25, 45),
// (25,52): error CS9075: Cannot return a parameter by reference 't' because it is scoped to the current method
// R F31<T>(out T t) { t = default; return F1(ref t); } // 4
Diagnostic(ErrorCode.ERR_RefReturnScopedParameter, "t").WithArguments("t").WithLocation(25, 52),
// (26,45): error CS8347: Cannot use a result of 'C.F2<T>(in T)' in this context because it may expose variables referenced by parameter 't' outside of their declaration scope
// R F32<T>(out T t) { t = default; return F2(in t); } // 5
Diagnostic(ErrorCode.ERR_EscapeCall, "F2(in t)").WithArguments("C.F2<T>(in T)", "t").WithLocation(26, 45),
// (26,51): error CS9075: Cannot return a parameter by reference 't' because it is scoped to the current method
// R F32<T>(out T t) { t = default; return F2(in t); } // 5
Diagnostic(ErrorCode.ERR_RefReturnScopedParameter, "t").WithArguments("t").WithLocation(26, 51),
// (27,45): error CS8347: Cannot use a result of 'C.F2<T>(in T)' in this context because it may expose variables referenced by parameter 't' outside of their declaration scope
// R F33<T>(out T t) { t = default; return F2(t); } // 6
Diagnostic(ErrorCode.ERR_EscapeCall, "F2(t)").WithArguments("C.F2<T>(in T)", "t").WithLocation(27, 45),
// (27,48): error CS9075: Cannot return a parameter by reference 't' because it is scoped to the current method
// R F33<T>(out T t) { t = default; return F2(t); } // 6
Diagnostic(ErrorCode.ERR_RefReturnScopedParameter, "t").WithArguments("t").WithLocation(27, 48)
};
var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10);
comp.VerifyDiagnostics(comp.Assembly.RuntimeSupportsByRefFields ? expectedUpdatedDiagnostics : expectedLegacyDiagnostics);
comp = CreateCompilation(source);
comp.VerifyEmitDiagnostics(expectedUpdatedDiagnostics);
}
[Fact]
public void MethodInvocation_Rvalue_06()
{
var source =
@"ref struct R<T>
{
}
class Program
{
static R<T> F0<T, U>(T t, U u) => throw null;
static R<T> F1<T, U>(T t, ref U u) => throw null;
static R<T> F2<T, U>(T t, in U u) => throw null;
static R<T> F3<T, U>(T t, out U u) => throw null;
static R<T> F4<T, U>(ref T t, ref U u) => throw null;
static R<T> F5<T, U>(ref T t, in U u) => throw null;
static R<T> F6<T, U>(ref T t, out U u) => throw null;
static R<T> F7<T, U>(in T t, in U u) => throw null;
static R<T> F8<T, U>(in T t, out U u) => throw null;
static R<T> F9<T, U>(out T t, out U u) => throw null;
static R<T> G0<T, U>()
{
T t = default;
U u = default;
return F0(t, u);
}
static R<T> G1<T, U>()
{
T t = default;
U u = default;
return F1(t, ref u); // 1
}
static R<T> G2A<T, U>()
{
T t = default;
U u = default;
return F2(t, in u); // 2
}
static R<T> G2B<T, U>()
{
T t = default;
U u = default;
return F2(t, u); // 3
}
static R<T> G3<T, U>()
{
T t = default;
U u = default;
return F3(t, out u);
}
static R<T> G4<T, U>()
{
T t = default;
U u = default;
return F4(ref t, ref u); // 4
}
static R<T> G5A<T, U>()
{
T t = default;
U u = default;
return F5(ref t, in u); // 5
}
static R<T> G5B<T, U>()
{
T t = default;
U u = default;
return F5(ref t, u); // 6
}
static R<T> G6<T, U>()
{
T t = default;
U u = default;
return F6(ref t, out u); // 7
}
static R<T> G7A<T, U>()
{
T t = default;
U u = default;
return F7(in t, in u); // 8
}
static R<T> G7B<T, U>()
{
T t = default;
U u = default;
return F7(t, u); // 9
}
static R<T> G8A<T, U>()
{
T t = default;
U u = default;
return F8(in t, out u); // 10
}
static R<T> G8B<T, U>()
{
T t = default;
U u = default;
return F8(t, out u); // 11
}
static R<T> G9<T, U>()
{
T t = default;
U u = default;
return F9(out t, out u);
}
}";
var expectedLegacyDiagnostics = new DiagnosticDescription[]
{
};
var expectedUpdatedDiagnostics = new DiagnosticDescription[]
{
// (26,16): error CS8347: Cannot use a result of 'Program.F1<T, U>(T, ref U)' in this context because it may expose variables referenced by parameter 'u' outside of their declaration scope
// return F1(t, ref u); // 1
Diagnostic(ErrorCode.ERR_EscapeCall, "F1(t, ref u)").WithArguments("Program.F1<T, U>(T, ref U)", "u").WithLocation(26, 16),
// (26,26): error CS8168: Cannot return local 'u' by reference because it is not a ref local
// return F1(t, ref u); // 1
Diagnostic(ErrorCode.ERR_RefReturnLocal, "u").WithArguments("u").WithLocation(26, 26),
// (32,16): error CS8347: Cannot use a result of 'Program.F2<T, U>(T, in U)' in this context because it may expose variables referenced by parameter 'u' outside of their declaration scope
// return F2(t, in u); // 2
Diagnostic(ErrorCode.ERR_EscapeCall, "F2(t, in u)").WithArguments("Program.F2<T, U>(T, in U)", "u").WithLocation(32, 16),
// (32,25): error CS8168: Cannot return local 'u' by reference because it is not a ref local
// return F2(t, in u); // 2
Diagnostic(ErrorCode.ERR_RefReturnLocal, "u").WithArguments("u").WithLocation(32, 25),
// (38,16): error CS8347: Cannot use a result of 'Program.F2<T, U>(T, in U)' in this context because it may expose variables referenced by parameter 'u' outside of their declaration scope
// return F2(t, u); // 3
Diagnostic(ErrorCode.ERR_EscapeCall, "F2(t, u)").WithArguments("Program.F2<T, U>(T, in U)", "u").WithLocation(38, 16),
// (38,22): error CS8168: Cannot return local 'u' by reference because it is not a ref local
// return F2(t, u); // 3
Diagnostic(ErrorCode.ERR_RefReturnLocal, "u").WithArguments("u").WithLocation(38, 22),
// (50,16): error CS8347: Cannot use a result of 'Program.F4<T, U>(ref T, ref U)' in this context because it may expose variables referenced by parameter 't' outside of their declaration scope
// return F4(ref t, ref u); // 4
Diagnostic(ErrorCode.ERR_EscapeCall, "F4(ref t, ref u)").WithArguments("Program.F4<T, U>(ref T, ref U)", "t").WithLocation(50, 16),
// (50,23): error CS8168: Cannot return local 't' by reference because it is not a ref local
// return F4(ref t, ref u); // 4
Diagnostic(ErrorCode.ERR_RefReturnLocal, "t").WithArguments("t").WithLocation(50, 23),
// (56,16): error CS8347: Cannot use a result of 'Program.F5<T, U>(ref T, in U)' in this context because it may expose variables referenced by parameter 't' outside of their declaration scope
// return F5(ref t, in u); // 5
Diagnostic(ErrorCode.ERR_EscapeCall, "F5(ref t, in u)").WithArguments("Program.F5<T, U>(ref T, in U)", "t").WithLocation(56, 16),
// (56,23): error CS8168: Cannot return local 't' by reference because it is not a ref local
// return F5(ref t, in u); // 5
Diagnostic(ErrorCode.ERR_RefReturnLocal, "t").WithArguments("t").WithLocation(56, 23),
// (62,16): error CS8347: Cannot use a result of 'Program.F5<T, U>(ref T, in U)' in this context because it may expose variables referenced by parameter 't' outside of their declaration scope
// return F5(ref t, u); // 6
Diagnostic(ErrorCode.ERR_EscapeCall, "F5(ref t, u)").WithArguments("Program.F5<T, U>(ref T, in U)", "t").WithLocation(62, 16),
// (62,23): error CS8168: Cannot return local 't' by reference because it is not a ref local
// return F5(ref t, u); // 6
Diagnostic(ErrorCode.ERR_RefReturnLocal, "t").WithArguments("t").WithLocation(62, 23),
// (68,16): error CS8347: Cannot use a result of 'Program.F6<T, U>(ref T, out U)' in this context because it may expose variables referenced by parameter 't' outside of their declaration scope
// return F6(ref t, out u); // 7
Diagnostic(ErrorCode.ERR_EscapeCall, "F6(ref t, out u)").WithArguments("Program.F6<T, U>(ref T, out U)", "t").WithLocation(68, 16),
// (68,23): error CS8168: Cannot return local 't' by reference because it is not a ref local
// return F6(ref t, out u); // 7
Diagnostic(ErrorCode.ERR_RefReturnLocal, "t").WithArguments("t").WithLocation(68, 23),
// (74,16): error CS8347: Cannot use a result of 'Program.F7<T, U>(in T, in U)' in this context because it may expose variables referenced by parameter 't' outside of their declaration scope
// return F7(in t, in u); // 8
Diagnostic(ErrorCode.ERR_EscapeCall, "F7(in t, in u)").WithArguments("Program.F7<T, U>(in T, in U)", "t").WithLocation(74, 16),
// (74,22): error CS8168: Cannot return local 't' by reference because it is not a ref local
// return F7(in t, in u); // 8
Diagnostic(ErrorCode.ERR_RefReturnLocal, "t").WithArguments("t").WithLocation(74, 22),
// (80,16): error CS8347: Cannot use a result of 'Program.F7<T, U>(in T, in U)' in this context because it may expose variables referenced by parameter 't' outside of their declaration scope
// return F7(t, u); // 9
Diagnostic(ErrorCode.ERR_EscapeCall, "F7(t, u)").WithArguments("Program.F7<T, U>(in T, in U)", "t").WithLocation(80, 16),
// (80,19): error CS8168: Cannot return local 't' by reference because it is not a ref local
// return F7(t, u); // 9
Diagnostic(ErrorCode.ERR_RefReturnLocal, "t").WithArguments("t").WithLocation(80, 19),
// (86,16): error CS8347: Cannot use a result of 'Program.F8<T, U>(in T, out U)' in this context because it may expose variables referenced by parameter 't' outside of their declaration scope
// return F8(in t, out u); // 10
Diagnostic(ErrorCode.ERR_EscapeCall, "F8(in t, out u)").WithArguments("Program.F8<T, U>(in T, out U)", "t").WithLocation(86, 16),
// (86,22): error CS8168: Cannot return local 't' by reference because it is not a ref local
// return F8(in t, out u); // 10
Diagnostic(ErrorCode.ERR_RefReturnLocal, "t").WithArguments("t").WithLocation(86, 22),
// (92,16): error CS8347: Cannot use a result of 'Program.F8<T, U>(in T, out U)' in this context because it may expose variables referenced by parameter 't' outside of their declaration scope
// return F8(t, out u); // 11
Diagnostic(ErrorCode.ERR_EscapeCall, "F8(t, out u)").WithArguments("Program.F8<T, U>(in T, out U)", "t").WithLocation(92, 16),
// (92,19): error CS8168: Cannot return local 't' by reference because it is not a ref local
// return F8(t, out u); // 11
Diagnostic(ErrorCode.ERR_RefReturnLocal, "t").WithArguments("t").WithLocation(92, 19)
};
var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10);
comp.VerifyDiagnostics(comp.Assembly.RuntimeSupportsByRefFields ? expectedUpdatedDiagnostics : expectedLegacyDiagnostics);
comp = CreateCompilation(source);
comp.VerifyEmitDiagnostics(expectedUpdatedDiagnostics);
}
[Fact]
public void MethodInvocation_Scoped_Lvalue()
{
var source =
@"
using System.Diagnostics.CodeAnalysis;
class Program
{
static ref T F0<T>(ref R<T> x, ref R<T> y) => throw null;
static ref T F2<T>(ref R<T> x, scoped ref R<T> y) => throw null;
static ref T F5<T>(scoped ref R<T> x, scoped ref R<T> y) => throw null;
static ref T F00<T>(ref R<T> x) { R<T> y = default; return ref F0(ref x, ref y); } // 1
static ref T F02<T>(ref R<T> x) { R<T> y = default; return ref F2(ref x, ref y); }
static ref T F05<T>(ref R<T> x) { R<T> y = default; return ref F5(ref x, ref y); }
static ref T F20<T>(scoped ref R<T> x) { R<T> y = default; return ref F0(ref x, ref y); } // 2
static ref T F22<T>(scoped ref R<T> x) { R<T> y = default; return ref F2(ref x, ref y); } // 3
static ref T F25<T>(scoped ref R<T> x) { R<T> y = default; return ref F5(ref x, ref y); }
}
ref struct R<T> { }
";
var comp = CreateCompilation(source);
comp.VerifyEmitDiagnostics(
// (9,68): error CS8347: Cannot use a result of 'Program.F0<T>(ref R<T>, ref R<T>)' in this context because it may expose variables referenced by parameter 'y' outside of their declaration scope
// static ref T F00<T>(ref R<T> x) { R<T> y = default; return ref F0(ref x, ref y); } // 1
Diagnostic(ErrorCode.ERR_EscapeCall, "F0(ref x, ref y)").WithArguments("Program.F0<T>(ref R<T>, ref R<T>)", "y").WithLocation(9, 68),
// (9,82): error CS8168: Cannot return local 'y' by reference because it is not a ref local
// static ref T F00<T>(ref R<T> x) { R<T> y = default; return ref F0(ref x, ref y); } // 1
Diagnostic(ErrorCode.ERR_RefReturnLocal, "y").WithArguments("y").WithLocation(9, 82),
// (13,75): error CS8347: Cannot use a result of 'Program.F0<T>(ref R<T>, ref R<T>)' in this context because it may expose variables referenced by parameter 'x' outside of their declaration scope
// static ref T F20<T>(scoped ref R<T> x) { R<T> y = default; return ref F0(ref x, ref y); } // 2
Diagnostic(ErrorCode.ERR_EscapeCall, "F0(ref x, ref y)").WithArguments("Program.F0<T>(ref R<T>, ref R<T>)", "x").WithLocation(13, 75),
// (13,82): error CS9075: Cannot return a parameter by reference 'x' because it is scoped to the current method
// static ref T F20<T>(scoped ref R<T> x) { R<T> y = default; return ref F0(ref x, ref y); } // 2
Diagnostic(ErrorCode.ERR_RefReturnScopedParameter, "x").WithArguments("x").WithLocation(13, 82),
// (14,75): error CS8347: Cannot use a result of 'Program.F2<T>(ref R<T>, scoped ref R<T>)' in this context because it may expose variables referenced by parameter 'x' outside of their declaration scope
// static ref T F22<T>(scoped ref R<T> x) { R<T> y = default; return ref F2(ref x, ref y); } // 3
Diagnostic(ErrorCode.ERR_EscapeCall, "F2(ref x, ref y)").WithArguments("Program.F2<T>(ref R<T>, scoped ref R<T>)", "x").WithLocation(14, 75),
// (14,82): error CS9075: Cannot return a parameter by reference 'x' because it is scoped to the current method
// static ref T F22<T>(scoped ref R<T> x) { R<T> y = default; return ref F2(ref x, ref y); } // 3
Diagnostic(ErrorCode.ERR_RefReturnScopedParameter, "x").WithArguments("x").WithLocation(14, 82));
}
[Fact]
public void MethodInvocation_Scoped_Rvalue()
{
var source =
@"ref struct R
{
public R(ref int i) { }
}
class Program
{
static R F0(R x, R y) => throw null;
static R F1(R x, scoped R y) => throw null;
static R F2(scoped R x, scoped R y) => throw null;
static R F00(R x, int i) { var y = new R(ref i); return F0(x, y); } // 1
static R F01(R x, int i) { var y = new R(ref i); return F1(x, y); }
static R F02(R x, int i) { var y = new R(ref i); return F2(x, y); }
static R F10(scoped R x, int i) { var y = new R(ref i); return F0(x, y); } // 2
static R F11(scoped R x, int i) { var y = new R(ref i); return F1(x, y); } // 3
static R F12(scoped R x, int i) { var y = new R(ref i); return F2(x, y); }
}";
var comp = CreateCompilation(source);
comp.VerifyEmitDiagnostics(
// (11,61): error CS8347: Cannot use a result of 'Program.F0(R, R)' in this context because it may expose variables referenced by parameter 'y' outside of their declaration scope
// static R F00(R x, int i) { var y = new R(ref i); return F0(x, y); } // 1
Diagnostic(ErrorCode.ERR_EscapeCall, "F0(x, y)").WithArguments("Program.F0(R, R)", "y").WithLocation(11, 61),
// (11,67): error CS8352: Cannot use variable 'y' in this context because it may expose referenced variables outside of their declaration scope
// static R F00(R x, int i) { var y = new R(ref i); return F0(x, y); } // 1
Diagnostic(ErrorCode.ERR_EscapeVariable, "y").WithArguments("y").WithLocation(11, 67),
// (15,68): error CS8347: Cannot use a result of 'Program.F0(R, R)' in this context because it may expose variables referenced by parameter 'x' outside of their declaration scope
// static R F10(scoped R x, int i) { var y = new R(ref i); return F0(x, y); } // 2
Diagnostic(ErrorCode.ERR_EscapeCall, "F0(x, y)").WithArguments("Program.F0(R, R)", "x").WithLocation(15, 68),
// (15,71): error CS8352: Cannot use variable 'scoped R x' in this context because it may expose referenced variables outside of their declaration scope
// static R F10(scoped R x, int i) { var y = new R(ref i); return F0(x, y); } // 2
Diagnostic(ErrorCode.ERR_EscapeVariable, "x").WithArguments("scoped R x").WithLocation(15, 71),
// (16,68): error CS8347: Cannot use a result of 'Program.F1(R, scoped R)' in this context because it may expose variables referenced by parameter 'x' outside of their declaration scope
// static R F11(scoped R x, int i) { var y = new R(ref i); return F1(x, y); } // 3
Diagnostic(ErrorCode.ERR_EscapeCall, "F1(x, y)").WithArguments("Program.F1(R, scoped R)", "x").WithLocation(16, 68),
// (16,71): error CS8352: Cannot use variable 'scoped R x' in this context because it may expose referenced variables outside of their declaration scope
// static R F11(scoped R x, int i) { var y = new R(ref i); return F1(x, y); } // 3
Diagnostic(ErrorCode.ERR_EscapeVariable, "x").WithArguments("scoped R x").WithLocation(16, 71));
}
[Fact]
public void MethodInvocation_Params()
{
var source =
@"ref struct R
{
public R(ref int i) { }
}
class Program
{
static R M1(R input, params object[] array)
{
return input;
}
static R M2()
{
int i = 42;
var r = new R(ref i);
return M1(r);
}
static R M3()
{
int i = 42;
var r = new R(ref i);
return M1(r, 0, 1, 2);
}
}";
var comp = CreateCompilation(source);
comp.VerifyEmitDiagnostics(
// (15,16): error CS8347: Cannot use a result of 'Program.M1(R, params object[])' in this context because it may expose variables referenced by parameter 'input' outside of their declaration scope
// return M1(r);
Diagnostic(ErrorCode.ERR_EscapeCall, "M1(r)").WithArguments("Program.M1(R, params object[])", "input").WithLocation(15, 16),
// (15,19): error CS8352: Cannot use variable 'r' in this context because it may expose referenced variables outside of their declaration scope
// return M1(r);
Diagnostic(ErrorCode.ERR_EscapeVariable, "r").WithArguments("r").WithLocation(15, 19),
// (21,16): error CS8347: Cannot use a result of 'Program.M1(R, params object[])' in this context because it may expose variables referenced by parameter 'input' outside of their declaration scope
// return M1(r, 0, 1, 2);
Diagnostic(ErrorCode.ERR_EscapeCall, "M1(r, 0, 1, 2)").WithArguments("Program.M1(R, params object[])", "input").WithLocation(21, 16),
// (21,19): error CS8352: Cannot use variable 'r' in this context because it may expose referenced variables outside of their declaration scope
// return M1(r, 0, 1, 2);
Diagnostic(ErrorCode.ERR_EscapeVariable, "r").WithArguments("r").WithLocation(21, 19));
}
[Fact]
public void MethodArgumentsMustMatch_01()
{
var source =
@"ref struct R
{
public void F0(ref R r) => throw null;
public void F2(scoped ref R r) => throw null;
}
class Program
{
static void F00(ref R x, ref R y) { x.F0(ref y); }
static void F02(ref R x, ref R y) { x.F2(ref y); }
static void F20(ref R x, scoped ref R y) { x.F0(ref y); }
static void F22(ref R x, scoped ref R y) { x.F2(ref y); }
static void F60(scoped ref R x, ref R y) { x.F0(ref y); }
static void F62(scoped ref R x, ref R y) { x.F2(ref y); }
static void F80(scoped ref R x, scoped ref R y) { x.F0(ref y); }
static void F82(scoped ref R x, scoped ref R y) { x.F2(ref y); }
}";
var comp = CreateCompilation(source);
// Should we also report ErrorCode.ERR_CallArgMixing for 3, 4, 5, 6? See the call to
// CheckValEscape() for the receiver at the end of CheckInvocationArgMixing().
comp.VerifyEmitDiagnostics();
}
[Fact]
public void MethodArgumentsMustMatch_02()
{
var source =
@"ref struct R
{
}
class Program
{
static void F0(ref R a, ref R b) => throw null;
static void F2(ref R a, scoped ref R b) => throw null;
static void F5(scoped ref R a, scoped ref R b) => throw null;
static void F00(ref R x, ref R y) { F0(ref x, ref y); }
static void F02(ref R x, ref R y) { F2(ref x, ref y); }
static void F05(ref R x, ref R y) { F5(ref x, ref y); }
static void F20(ref R x, scoped ref R y) { F0(ref x, ref y); }
static void F22(ref R x, scoped ref R y) { F2(ref x, ref y); }
static void F25(ref R x, scoped ref R y) { F5(ref x, ref y); }
static void F50(scoped ref R x, scoped ref R y) { F0(ref x, ref y); }
static void F52(scoped ref R x, scoped ref R y) { F2(ref x, ref y); }
static void F55(scoped ref R x, scoped ref R y) { F5(ref x, ref y); }
}";
var comp = CreateCompilation(source);
comp.VerifyEmitDiagnostics();
}
[Fact]
public void MethodArgumentsMustMatch_03()
{
var source =
@"ref struct R<T>
{
public R(ref T t) { }
}
class Program
{
static void F0<T>(ref R<T> a, ref R<T> b) => throw null;
static void F2<T>(ref R<T> a, scoped ref R<T> b) => throw null;
static void F5<T>(scoped ref R<T> a, scoped ref R<T> b) => throw null;
static void F<T>(ref R<T> x)
{
T t = default;
R<T> y = new R<T>(ref t);
F0(ref x, ref x);
F2(ref x, ref x);
F5(ref x, ref x);
F0(ref x, ref y); // 1
F2(ref x, ref y); // 2
F5(ref x, ref y); // 3
F0(ref y, ref x); // 4
F2(ref y, ref x); // 5
F5(ref y, ref x); // 6
F0(ref y, ref y);
F2(ref y, ref y);
F5(ref y, ref y);
}
}";
var comp = CreateCompilation(source);
comp.VerifyEmitDiagnostics(
// (20,9): error CS8350: This combination of arguments to 'Program.F0<T>(ref R<T>, ref R<T>)' is disallowed because it may expose variables referenced by parameter 'b' outside of their declaration scope
// F0(ref x, ref y); // 1
Diagnostic(ErrorCode.ERR_CallArgMixing, "F0(ref x, ref y)").WithArguments("Program.F0<T>(ref R<T>, ref R<T>)", "b").WithLocation(20, 9),
// (20,23): error CS8352: Cannot use variable 'y' in this context because it may expose referenced variables outside of their declaration scope
// F0(ref x, ref y); // 1
Diagnostic(ErrorCode.ERR_EscapeVariable, "y").WithArguments("y").WithLocation(20, 23),
// (21,9): error CS8350: This combination of arguments to 'Program.F2<T>(ref R<T>, scoped ref R<T>)' is disallowed because it may expose variables referenced by parameter 'b' outside of their declaration scope
// F2(ref x, ref y); // 2
Diagnostic(ErrorCode.ERR_CallArgMixing, "F2(ref x, ref y)").WithArguments("Program.F2<T>(ref R<T>, scoped ref R<T>)", "b").WithLocation(21, 9),
// (21,23): error CS8352: Cannot use variable 'y' in this context because it may expose referenced variables outside of their declaration scope
// F2(ref x, ref y); // 2
Diagnostic(ErrorCode.ERR_EscapeVariable, "y").WithArguments("y").WithLocation(21, 23),
// (22,9): error CS8350: This combination of arguments to 'Program.F5<T>(scoped ref R<T>, scoped ref R<T>)' is disallowed because it may expose variables referenced by parameter 'b' outside of their declaration scope
// F5(ref x, ref y); // 3
Diagnostic(ErrorCode.ERR_CallArgMixing, "F5(ref x, ref y)").WithArguments("Program.F5<T>(scoped ref R<T>, scoped ref R<T>)", "b").WithLocation(22, 9),
// (22,23): error CS8352: Cannot use variable 'y' in this context because it may expose referenced variables outside of their declaration scope
// F5(ref x, ref y); // 3
Diagnostic(ErrorCode.ERR_EscapeVariable, "y").WithArguments("y").WithLocation(22, 23),
// (24,9): error CS8350: This combination of arguments to 'Program.F0<T>(ref R<T>, ref R<T>)' is disallowed because it may expose variables referenced by parameter 'a' outside of their declaration scope
// F0(ref y, ref x); // 4
Diagnostic(ErrorCode.ERR_CallArgMixing, "F0(ref y, ref x)").WithArguments("Program.F0<T>(ref R<T>, ref R<T>)", "a").WithLocation(24, 9),
// (24,16): error CS8352: Cannot use variable 'y' in this context because it may expose referenced variables outside of their declaration scope
// F0(ref y, ref x); // 4
Diagnostic(ErrorCode.ERR_EscapeVariable, "y").WithArguments("y").WithLocation(24, 16),
// (25,9): error CS8350: This combination of arguments to 'Program.F2<T>(ref R<T>, scoped ref R<T>)' is disallowed because it may expose variables referenced by parameter 'a' outside of their declaration scope
// F2(ref y, ref x); // 5
Diagnostic(ErrorCode.ERR_CallArgMixing, "F2(ref y, ref x)").WithArguments("Program.F2<T>(ref R<T>, scoped ref R<T>)", "a").WithLocation(25, 9),
// (25,16): error CS8352: Cannot use variable 'y' in this context because it may expose referenced variables outside of their declaration scope
// F2(ref y, ref x); // 5
Diagnostic(ErrorCode.ERR_EscapeVariable, "y").WithArguments("y").WithLocation(25, 16),
// (26,9): error CS8350: This combination of arguments to 'Program.F5<T>(scoped ref R<T>, scoped ref R<T>)' is disallowed because it may expose variables referenced by parameter 'a' outside of their declaration scope
// F5(ref y, ref x); // 6
Diagnostic(ErrorCode.ERR_CallArgMixing, "F5(ref y, ref x)").WithArguments("Program.F5<T>(scoped ref R<T>, scoped ref R<T>)", "a").WithLocation(26, 9),
// (26,16): error CS8352: Cannot use variable 'y' in this context because it may expose referenced variables outside of their declaration scope
// F5(ref y, ref x); // 6
Diagnostic(ErrorCode.ERR_EscapeVariable, "y").WithArguments("y").WithLocation(26, 16));
}
[Fact]
public void MethodArgumentsMustMatch_04()
{
var source =
@"ref struct R { }
class Program
{
static void F0(ref R x, in R y) => throw null;
static void F2(ref R x, scoped in R y) => throw null;
static void F00(ref R x, in R y) { F0(ref x, in y); }
static void F02(ref R x, in R y) { F2(ref x, in y); }
static void F20(ref R x, scoped in R y) { F0(ref x, in y); }
static void F22(ref R x, scoped in R y) { F2(ref x, in y); }
}";
var comp = CreateCompilation(source);
comp.VerifyEmitDiagnostics();
}
[Fact]
public void MethodArgumentsMustMatch_05()
{
var source =
@"ref struct R { }
class Program
{
static void F0(ref R x, out R y) => throw null;
static void F2(ref R x, scoped out R y) => throw null;
static void F00(ref R x, out R y) { F0(ref x, out y); }
static void F02(ref R x, out R y) { F2(ref x, out y); }
static void F20(ref R x, scoped out R y) { F0(ref x, out y); }
static void F22(ref R x, scoped out R y) { F2(ref x, out y); }
}";
var comp = CreateCompilation(source);
comp.VerifyEmitDiagnostics();
}
[Fact]
public void MethodArgumentsMustMatch_06()
{
var source =
@"ref struct R { }
class Program
{
static void F0(__arglist) { }
static void F1(ref R a, __arglist) { }
static void F00(ref R x, ref R y) { F0(__arglist(ref x, ref y)); } // 1
static void F01(ref R x, ref R y) { F1(ref x, __arglist(ref y)); } // 2
static void F20(ref R x, scoped ref R y) { F0(__arglist(ref x, ref y)); } // 3
static void F21(ref R x, scoped ref R y) { F1(ref x, __arglist(ref y)); } // 4
static void F50(scoped ref R x, scoped ref R y) { F0(__arglist(ref x, ref y)); } // 5
static void F51(scoped ref R x, scoped ref R y) { F1(ref x, __arglist(ref y)); } // 6
}";
var comp = CreateCompilation(source);
comp.VerifyEmitDiagnostics();
}
[Fact]
public void MethodArgumentsMustMatch_07_1()
{
var source =
@"
ref struct R { }
class Program
{
static void F0(__arglist) { }
static void F1(scoped ref R a, __arglist) { }
static void F00(scoped ref R x, scoped ref R y) { F0(__arglist(ref x, ref y)); } // 1
static void F01(scoped ref R x, scoped ref R y) { F1(ref x, __arglist(ref y)); } // 2
static void F20(scoped ref R x, ref R y) { F0(__arglist(ref x, ref y)); } // 3
static void F21(scoped ref R x, ref R y) { F1(ref x, __arglist(ref y)); } // 4
static void F50(ref R x, ref R y) { F0(__arglist(ref x, ref y)); } // 5
static void F51(ref R x, ref R y) { F1(ref x, __arglist(ref y)); } // 6
}";
var comp = CreateCompilation(source);
comp.VerifyEmitDiagnostics();
}
[Fact(Skip = "https://github.com/dotnet/roslyn/issues/64471")]
public void MethodArgumentsMustMatch_07_2()
{
var source =
@"
using System.Diagnostics.CodeAnalysis;
using System;
ref struct R
{
public byte B;
public ref byte RB;
}
class Program
{
static R F0(__arglist)
{
var args = new ArgIterator(__arglist);
ref R r = ref __refvalue(args.GetNextArg(), R);
r.RB = ref r.B; // 1
return r;
}
static void F1(scoped ref R y) { F0(__arglist(ref y)); } // 2
static void F2(ref R y) { F0(__arglist(ref y)); } // 3
static R F3(scoped ref R y) { return F0(__arglist(ref y)); } // 4
static R F4(ref R y) { return F0(__arglist(ref y)); } // 5
}";
// __refvalue operators can only ref-escape to current method.
// The __arglist operator here assumes that `F0` could do `y.RB = ref y`.
// These assumptions are contradictory, but it just ends up being more strict in both directions.
// Tracking in https://github.com/dotnet/roslyn/issues/64130
var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70);
comp.VerifyEmitDiagnostics(
// (17,9): error CS8374: Cannot ref-assign 'r.B' to 'RB' because 'r.B' has a narrower escape scope than 'RB'.
// r.RB = ref r.B; // 1
Diagnostic(ErrorCode.ERR_RefAssignNarrower, "r.RB = ref r.B").WithArguments("RB", "r.B").WithLocation(17, 9));
}
[Fact(Skip = "https://github.com/dotnet/roslyn/issues/64471")]
public void MethodArgumentsMustMatch_07_3()
{
// demonstrate the non-ref-fields behavior.
var source =
@"
using System;
class Program
{
static ref int F0(__arglist)
{
var args = new ArgIterator(__arglist);
ref int r = ref __refvalue(args.GetNextArg(), int);
return ref r; // 1
}
static void F1(scoped ref int y) { F0(__arglist(ref y)); }
static void F2(ref int y) { F0(__arglist(ref y)); }
static ref int F3(scoped ref int y) { return ref F0(__arglist(ref y)); }
static ref int F4(ref int y) { return ref F0(__arglist(ref y)); }
}";
var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70);
comp.VerifyEmitDiagnostics(
// (10,20): 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(10, 20));
}
/// <summary>
/// ref to ref struct in __arglist is unscoped ref.
/// </summary>
[Fact]
public void MethodArgumentsMustMatch_08()
{
var source =
@"ref struct R<T>
{
public R(ref T t) { }
}
class Program
{
static void F0(__arglist) { }
static void F1()
{
var x = new R<int>();
int i = 1;
var y = new R<int>(ref i);
F0(__arglist(ref x)); // 1
F0(__arglist(ref y));
F0(__arglist(ref x, ref x)); // 2
F0(__arglist(ref x, ref y)); // 3
F0(__arglist(ref y, ref x)); // 4
F0(__arglist(ref y, ref y));
}
}";
var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10);
comp.VerifyEmitDiagnostics();
comp = CreateCompilation(source);
comp.VerifyEmitDiagnostics(
// (16,9): error CS8350: This combination of arguments to 'Program.F0(__arglist)' is disallowed because it may expose variables referenced by parameter '__arglist' outside of their declaration scope
// F0(__arglist(ref x, ref y)); // 3
Diagnostic(ErrorCode.ERR_CallArgMixing, "F0(__arglist(ref x, ref y))").WithArguments("Program.F0(__arglist)", "__arglist").WithLocation(16, 9),
// (16,33): error CS8352: Cannot use variable 'y' in this context because it may expose referenced variables outside of their declaration scope
// F0(__arglist(ref x, ref y)); // 3
Diagnostic(ErrorCode.ERR_EscapeVariable, "y").WithArguments("y").WithLocation(16, 33),
// (17,9): error CS8350: This combination of arguments to 'Program.F0(__arglist)' is disallowed because it may expose variables referenced by parameter '__arglist' outside of their declaration scope
// F0(__arglist(ref y, ref x)); // 4
Diagnostic(ErrorCode.ERR_CallArgMixing, "F0(__arglist(ref y, ref x))").WithArguments("Program.F0(__arglist)", "__arglist").WithLocation(17, 9),
// (17,26): error CS8352: Cannot use variable 'y' in this context because it may expose referenced variables outside of their declaration scope
// F0(__arglist(ref y, ref x)); // 4
Diagnostic(ErrorCode.ERR_EscapeVariable, "y").WithArguments("y").WithLocation(17, 26));
}
/// <summary>
/// ref to ref struct in __arglist is unscoped ref.
/// </summary>
[Fact]
public void MethodArgumentsMustMatch_09()
{
var source =
@"ref struct R<T>
{
public R(ref T t) { }
}
class Program
{
static void F0(ref R<int> a, __arglist) { }
static void F1()
{
var x = new R<int>();
int i = 1;
var y = new R<int>(ref i);
F0(ref x, __arglist(ref x)); // 1
F0(ref x, __arglist(ref y)); // 2
F0(ref y, __arglist(ref x)); // 3
F0(ref y, __arglist(ref y));
}
}";
var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10);
comp.VerifyEmitDiagnostics();
comp = CreateCompilation(source);
comp.VerifyEmitDiagnostics(
// (14,9): error CS8350: This combination of arguments to 'Program.F0(ref R<int>, __arglist)' is disallowed because it may expose variables referenced by parameter '__arglist' outside of their declaration scope
// F0(ref x, __arglist(ref y)); // 2
Diagnostic(ErrorCode.ERR_CallArgMixing, "F0(ref x, __arglist(ref y))").WithArguments("Program.F0(ref R<int>, __arglist)", "__arglist").WithLocation(14, 9),
// (14,33): error CS8352: Cannot use variable 'y' in this context because it may expose referenced variables outside of their declaration scope
// F0(ref x, __arglist(ref y)); // 2
Diagnostic(ErrorCode.ERR_EscapeVariable, "y").WithArguments("y").WithLocation(14, 33),
// (15,9): error CS8350: This combination of arguments to 'Program.F0(ref R<int>, __arglist)' is disallowed because it may expose variables referenced by parameter 'a' outside of their declaration scope
// F0(ref y, __arglist(ref x)); // 3
Diagnostic(ErrorCode.ERR_CallArgMixing, "F0(ref y, __arglist(ref x))").WithArguments("Program.F0(ref R<int>, __arglist)", "a").WithLocation(15, 9),
// (15,16): error CS8352: Cannot use variable 'y' in this context because it may expose referenced variables outside of their declaration scope
// F0(ref y, __arglist(ref x)); // 3
Diagnostic(ErrorCode.ERR_EscapeVariable, "y").WithArguments("y").WithLocation(15, 16));
}
[Fact]
public void MethodArgumentsMustMatch_10()
{
var source =
@"
ref struct R
{
public R(ref int i) { }
}
class Program
{
static void F1()
{
R r1 = default;
F2(ref r1);
F3(ref r1);
}
static void F2(scoped ref R r2)
{
}
static void F3(ref R r3)
{
}
}";
var comp = CreateCompilation(source);
comp.VerifyDiagnostics();
}
[Fact]
public void MethodArgumentsMustMatch_11()
{
var source =
@"
ref struct R
{
public R(ref int i) { }
}
class Program
{
static void F1()
{
R x1 = default;
R y1 = default;
F2(ref x1, ref y1);
F2(ref y1, ref x1);
}
static void F2(scoped ref R x2, ref R y2)
{
}
}";
var comp = CreateCompilation(source);
comp.VerifyDiagnostics();
}
[Fact]
public void MethodArgumentsMustMatch_12()
{
var source =
@"ref struct R
{
public R(ref int i) { }
}
class Program
{
static void F1()
{
R x1 = default;
int i = 42;
R y1 = new R(ref i); // implicitly scoped
F2(ref x1, ref y1); // 1
F2(ref y1, ref x1); // 2
}
static void F2(ref R x2, ref R y2)
{
}
}";
var comp = CreateCompilation(source);
comp.VerifyDiagnostics(
// (12,9): error CS8350: This combination of arguments to 'Program.F2(ref R, ref R)' is disallowed because it may expose variables referenced by parameter 'y2' outside of their declaration scope
// F2(ref x1, ref y1); // 1
Diagnostic(ErrorCode.ERR_CallArgMixing, "F2(ref x1, ref y1)").WithArguments("Program.F2(ref R, ref R)", "y2").WithLocation(12, 9),
// (12,24): error CS8352: Cannot use variable 'y1' in this context because it may expose referenced variables outside of their declaration scope
// F2(ref x1, ref y1); // 1
Diagnostic(ErrorCode.ERR_EscapeVariable, "y1").WithArguments("y1").WithLocation(12, 24),
// (13,9): error CS8350: This combination of arguments to 'Program.F2(ref R, ref R)' is disallowed because it may expose variables referenced by parameter 'x2' outside of their declaration scope
// F2(ref y1, ref x1); // 2
Diagnostic(ErrorCode.ERR_CallArgMixing, "F2(ref y1, ref x1)").WithArguments("Program.F2(ref R, ref R)", "x2").WithLocation(13, 9),
// (13,16): error CS8352: Cannot use variable 'y1' in this context because it may expose referenced variables outside of their declaration scope
// F2(ref y1, ref x1); // 2
Diagnostic(ErrorCode.ERR_EscapeVariable, "y1").WithArguments("y1").WithLocation(13, 16));
}
/// <summary>
/// Ensure that readonly members / types are properly accounted for
/// </summary>
[Fact]
public void MethodArgumentsMustMatch_13()
{
var source = """
ref struct RWRS
{
public void M1(RS rs) { }
public readonly void M2(RS rs) { }
}
readonly ref struct RORS
{
public void M3(RS rs) { }
}
ref struct RS
{
static void Test()
{
scoped RS local = default;
RWRS rwLocal = default;
rwLocal.M1(local); // 1
rwLocal.M2(local);
RORS roLocal = default;
roLocal.M3(local);
}
}
""";
var comp = CreateCompilation(new[] { source });
comp.VerifyDiagnostics(
// (16,9): error CS8350: This combination of arguments to 'RWRS.M1(RS)' is disallowed because it may expose variables referenced by parameter 'rs' outside of their declaration scope
// rwLocal.M1(local); // 1
Diagnostic(ErrorCode.ERR_CallArgMixing, "rwLocal.M1(local)").WithArguments("RWRS.M1(RS)", "rs").WithLocation(16, 9),
// (16,20): error CS8352: Cannot use variable 'local' in this context because it may expose referenced variables outside of their declaration scope
// rwLocal.M1(local); // 1
Diagnostic(ErrorCode.ERR_EscapeVariable, "local").WithArguments("local").WithLocation(16, 20));
}
[Fact]
public void MethodArgumentsMustMatch_14()
{
var source = """
using System.Diagnostics.CodeAnalysis;
ref struct R
{
public R(ref int i) { }
}
class Program
{
static void F0(ref R r0, [UnscopedRef] ref int i0)
{
}
static void F1(ref R x1)
{
int i1 = 1;
F0(ref x1, ref i1); // 1
R y1 = default;
F0(ref y1, ref i1); // 2
scoped R z1 = default;
F0(ref z1, ref i1);
}
static void F2(ref R x2, ref int i2)
{
F0(ref x2, ref i2); // 3
R y2 = default;
F0(ref y2, ref i2); // 4
scoped R z2 = default;
F0(ref z2, ref i2);
}
static void F3(ref R x3, [UnscopedRef] ref int i3)
{
F0(ref x3, ref i3);
R y3 = default;
F0(ref y3, ref i3);
scoped R z3 = default;
F0(ref z3, ref i3);
}
}
""";
var comp = CreateCompilation(new[] { source, UnscopedRefAttributeDefinition });
comp.VerifyDiagnostics(
// (14,9): error CS8350: This combination of arguments to 'Program.F0(ref R, ref int)' is disallowed because it may expose variables referenced by parameter 'i0' outside of their declaration scope
// F0(ref x1, ref i1); // 1
Diagnostic(ErrorCode.ERR_CallArgMixing, "F0(ref x1, ref i1)").WithArguments("Program.F0(ref R, ref int)", "i0").WithLocation(14, 9),
// (14,24): error CS8168: Cannot return local 'i1' by reference because it is not a ref local
// F0(ref x1, ref i1); // 1
Diagnostic(ErrorCode.ERR_RefReturnLocal, "i1").WithArguments("i1").WithLocation(14, 24),
// (16,9): error CS8350: This combination of arguments to 'Program.F0(ref R, ref int)' is disallowed because it may expose variables referenced by parameter 'i0' outside of their declaration scope
// F0(ref y1, ref i1); // 2
Diagnostic(ErrorCode.ERR_CallArgMixing, "F0(ref y1, ref i1)").WithArguments("Program.F0(ref R, ref int)", "i0").WithLocation(16, 9),
// (16,24): error CS8168: Cannot return local 'i1' by reference because it is not a ref local
// F0(ref y1, ref i1); // 2
Diagnostic(ErrorCode.ERR_RefReturnLocal, "i1").WithArguments("i1").WithLocation(16, 24),
// (22,9): error CS8350: This combination of arguments to 'Program.F0(ref R, ref int)' is disallowed because it may expose variables referenced by parameter 'i0' outside of their declaration scope
// F0(ref x2, ref i2); // 3
Diagnostic(ErrorCode.ERR_CallArgMixing, "F0(ref x2, ref i2)").WithArguments("Program.F0(ref R, ref int)", "i0").WithLocation(22, 9),
// (22,24): error CS9077: Cannot return a parameter by reference 'i2' through a ref parameter; it can only be returned in a return statement
// F0(ref x2, ref i2); // 3
Diagnostic(ErrorCode.ERR_RefReturnOnlyParameter, "i2").WithArguments("i2").WithLocation(22, 24),
// (24,9): error CS8350: This combination of arguments to 'Program.F0(ref R, ref int)' is disallowed because it may expose variables referenced by parameter 'i0' outside of their declaration scope
// F0(ref y2, ref i2); // 4
Diagnostic(ErrorCode.ERR_CallArgMixing, "F0(ref y2, ref i2)").WithArguments("Program.F0(ref R, ref int)", "i0").WithLocation(24, 9),
// (24,24): error CS9077: Cannot return a parameter by reference 'i2' through a ref parameter; it can only be returned in a return statement
// F0(ref y2, ref i2); // 4
Diagnostic(ErrorCode.ERR_RefReturnOnlyParameter, "i2").WithArguments("i2").WithLocation(24, 24));
}
// As above, but with in parameters.
[Fact]
public void MethodArgumentsMustMatch_15()
{
var source = """
using System.Diagnostics.CodeAnalysis;
ref struct R
{
public R(in int i) { }
}
class Program
{
static void F0(ref R r0, [UnscopedRef] in int i0)
{
}
static void F1(ref R x1)
{
int i1 = 1;
F0(ref x1, in i1); // 1
R y1 = default;
F0(ref y1, in i1); // 2
scoped R z1 = default;
F0(ref z1, in i1);
}
static void F2(ref R x2, in int i2)
{
F0(ref x2, in i2); // 3
R y2 = default;
F0(ref y2, in i2); // 4
scoped R z2 = default;
F0(ref z2, in i2);
}
static void F3(ref R x3, [UnscopedRef] in int i3)
{
F0(ref x3, in i3);
R y3 = default;
F0(ref y3, in i3);
scoped R z3 = default;
F0(ref z3, in i3);
}
}
""";
var comp = CreateCompilation(new[] { source, UnscopedRefAttributeDefinition });
comp.VerifyDiagnostics(
// (14,9): error CS8350: This combination of arguments to 'Program.F0(ref R, in int)' is disallowed because it may expose variables referenced by parameter 'i0' outside of their declaration scope
// F0(ref x1, in i1); // 1
Diagnostic(ErrorCode.ERR_CallArgMixing, "F0(ref x1, in i1)").WithArguments("Program.F0(ref R, in int)", "i0").WithLocation(14, 9),
// (14,23): error CS8168: Cannot return local 'i1' by reference because it is not a ref local
// F0(ref x1, in i1); // 1
Diagnostic(ErrorCode.ERR_RefReturnLocal, "i1").WithArguments("i1").WithLocation(14, 23),
// (16,9): error CS8350: This combination of arguments to 'Program.F0(ref R, in int)' is disallowed because it may expose variables referenced by parameter 'i0' outside of their declaration scope
// F0(ref y1, in i1); // 2
Diagnostic(ErrorCode.ERR_CallArgMixing, "F0(ref y1, in i1)").WithArguments("Program.F0(ref R, in int)", "i0").WithLocation(16, 9),
// (16,23): error CS8168: Cannot return local 'i1' by reference because it is not a ref local
// F0(ref y1, in i1); // 2
Diagnostic(ErrorCode.ERR_RefReturnLocal, "i1").WithArguments("i1").WithLocation(16, 23),
// (22,9): error CS8350: This combination of arguments to 'Program.F0(ref R, in int)' is disallowed because it may expose variables referenced by parameter 'i0' outside of their declaration scope
// F0(ref x2, in i2); // 3
Diagnostic(ErrorCode.ERR_CallArgMixing, "F0(ref x2, in i2)").WithArguments("Program.F0(ref R, in int)", "i0").WithLocation(22, 9),
// (22,23): error CS9077: Cannot return a parameter by reference 'i2' through a ref parameter; it can only be returned in a return statement
// F0(ref x2, in i2); // 3
Diagnostic(ErrorCode.ERR_RefReturnOnlyParameter, "i2").WithArguments("i2").WithLocation(22, 23),
// (24,9): error CS8350: This combination of arguments to 'Program.F0(ref R, in int)' is disallowed because it may expose variables referenced by parameter 'i0' outside of their declaration scope
// F0(ref y2, in i2); // 4
Diagnostic(ErrorCode.ERR_CallArgMixing, "F0(ref y2, in i2)").WithArguments("Program.F0(ref R, in int)", "i0").WithLocation(24, 9),
// (24,23): error CS9077: Cannot return a parameter by reference 'i2' through a ref parameter; it can only be returned in a return statement
// F0(ref y2, in i2); // 4
Diagnostic(ErrorCode.ERR_RefReturnOnlyParameter, "i2").WithArguments("i2").WithLocation(24, 23));
}
[Fact]
public void MethodArgumentsMustMatch_16()
{
var source = """
using System.Diagnostics.CodeAnalysis;
ref struct R
{
public ref int FA() => throw null;
[UnscopedRef] public ref int FB() => throw null;
}
class Program
{
static void F1(ref R r1, ref int i1) { }
static void F2(ref R r2, [UnscopedRef] ref int i2) { }
static void F(ref R x)
{
R y = default;
F1(ref x, ref y.FA());
F1(ref x, ref y.FB());
F2(ref x, ref y.FA());
F2(ref x, ref y.FB()); // 1
}
}
""";
var comp = CreateCompilation(new[] { source, UnscopedRefAttributeDefinition });
comp.VerifyDiagnostics(
// (17,9): error CS8350: This combination of arguments to 'Program.F2(ref R, ref int)' is disallowed because it may expose variables referenced by parameter 'i2' outside of their declaration scope
// F2(ref x, ref y.FB()); // 1
Diagnostic(ErrorCode.ERR_CallArgMixing, "F2(ref x, ref y.FB())").WithArguments("Program.F2(ref R, ref int)", "i2").WithLocation(17, 9),
// (17,23): error CS8168: Cannot return local 'y' by reference because it is not a ref local
// F2(ref x, ref y.FB()); // 1
Diagnostic(ErrorCode.ERR_RefReturnLocal, "y").WithArguments("y").WithLocation(17, 23));
}
// As above, but with in parameters.
[Fact]
public void MethodArgumentsMustMatch_17()
{
var source = """
using System.Diagnostics.CodeAnalysis;
ref struct R
{
public ref int FA() => throw null;
[UnscopedRef] public ref int FB() => throw null;
}
class Program
{
static void F1(ref R r1, in int i1) { }
static void F2(ref R r2, [UnscopedRef] in int i2) { }
static void F(ref R x)
{
R y = default;
F1(ref x, y.FA());
F1(ref x, y.FB());
F2(ref x, y.FA());
F2(ref x, y.FB()); // 1
F1(ref x, in y.FA());
F1(ref x, in y.FB());
F2(ref x, in y.FA());
F2(ref x, in y.FB()); // 2
}
}
""";
var comp = CreateCompilation(new[] { source, UnscopedRefAttributeDefinition });
comp.VerifyDiagnostics(
// (17,9): error CS8350: This combination of arguments to 'Program.F2(ref R, in int)' is disallowed because it may expose variables referenced by parameter 'i2' outside of their declaration scope
// F2(ref x, y.FB()); // 1
Diagnostic(ErrorCode.ERR_CallArgMixing, "F2(ref x, y.FB())").WithArguments("Program.F2(ref R, in int)", "i2").WithLocation(17, 9),
// (17,19): error CS8168: Cannot return local 'y' by reference because it is not a ref local
// F2(ref x, y.FB()); // 1
Diagnostic(ErrorCode.ERR_RefReturnLocal, "y").WithArguments("y").WithLocation(17, 19),
// (21,9): error CS8350: This combination of arguments to 'Program.F2(ref R, in int)' is disallowed because it may expose variables referenced by parameter 'i2' outside of their declaration scope
// F2(ref x, in y.FB()); // 2
Diagnostic(ErrorCode.ERR_CallArgMixing, "F2(ref x, in y.FB())").WithArguments("Program.F2(ref R, in int)", "i2").WithLocation(21, 9),
// (21,22): error CS8168: Cannot return local 'y' by reference because it is not a ref local
// F2(ref x, in y.FB()); // 2
Diagnostic(ErrorCode.ERR_RefReturnLocal, "y").WithArguments("y").WithLocation(21, 22));
}
// As above, but with ref readonly returns.
[Fact]
public void MethodArgumentsMustMatch_18()
{
var source = """
using System.Diagnostics.CodeAnalysis;
ref struct R
{
public ref readonly int FA() => throw null;
[UnscopedRef] public ref readonly int FB() => throw null;
}
class Program
{
static void F1(ref R r1, in int i1) { }
static void F2(ref R r2, [UnscopedRef] in int i2) { }
static void F(ref R x)
{
R y = default;
F1(ref x, y.FA());
F1(ref x, y.FB());
F2(ref x, y.FA());
F2(ref x, y.FB()); // 1
F1(ref x, in y.FA());
F1(ref x, in y.FB());
F2(ref x, in y.FA());
F2(ref x, in y.FB()); // 2
}
}
""";
var comp = CreateCompilation(new[] { source, UnscopedRefAttributeDefinition });
comp.VerifyDiagnostics(
// (17,9): error CS8350: This combination of arguments to 'Program.F2(ref R, in int)' is disallowed because it may expose variables referenced by parameter 'i2' outside of their declaration scope
// F2(ref x, y.FB()); // 1
Diagnostic(ErrorCode.ERR_CallArgMixing, "F2(ref x, y.FB())").WithArguments("Program.F2(ref R, in int)", "i2").WithLocation(17, 9),
// (17,19): error CS8168: Cannot return local 'y' by reference because it is not a ref local
// F2(ref x, y.FB()); // 1
Diagnostic(ErrorCode.ERR_RefReturnLocal, "y").WithArguments("y").WithLocation(17, 19),
// (21,9): error CS8350: This combination of arguments to 'Program.F2(ref R, in int)' is disallowed because it may expose variables referenced by parameter 'i2' outside of their declaration scope
// F2(ref x, in y.FB()); // 2
Diagnostic(ErrorCode.ERR_CallArgMixing, "F2(ref x, in y.FB())").WithArguments("Program.F2(ref R, in int)", "i2").WithLocation(21, 9),
// (21,22): error CS8168: Cannot return local 'y' by reference because it is not a ref local
// F2(ref x, in y.FB()); // 2
Diagnostic(ErrorCode.ERR_RefReturnLocal, "y").WithArguments("y").WithLocation(21, 22));
}
[Theory]
[InlineData(LanguageVersion.CSharp10)]
[InlineData(LanguageVersion.CSharp11)]
public void Arglist_RefToRefStruct(LanguageVersion languageVersion)
{
var source =
@"using System;
ref struct R<T>
{
}
class Program
{
static ref R<int> F(__arglist)
{
var args = new ArgIterator(__arglist);
ref R<int> r = ref __refvalue(args.GetNextArg(), R<int>);
return ref r;
}
}";
var comp = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion));
comp.VerifyEmitDiagnostics(
// (11,20): 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(11, 20));
}
[Theory]
[InlineData(LanguageVersion.CSharp10)]
[InlineData(LanguageVersion.CSharp11)]
public void Arglist_RefReturnedAsRef(LanguageVersion languageVersion)
{
var source =
@"using System;
class Program
{
static ref int F1(__arglist)
{
var args = new ArgIterator(__arglist);
return ref __refvalue(args.GetNextArg(), int);
}
static ref int F2()
{
int i = 2;
return ref F1(__arglist(ref i));
}
}";
var comp = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion));
comp.VerifyEmitDiagnostics(
// (7,20): error CS8156: An expression cannot be used in this context because it may not be passed or returned by reference
// return ref __refvalue(args.GetNextArg(), int);
Diagnostic(ErrorCode.ERR_RefReturnLvalueExpected, "__refvalue(args.GetNextArg(), int)").WithLocation(7, 20));
}
[Fact]
public void Arglist_RefReturnedAsRefStruct()
{
var source =
@"using System;
ref struct R<T>
{
public R(ref T t) { }
}
class Program
{
static R<int> F1(__arglist)
{
var args = new ArgIterator(__arglist);
ref int i = ref __refvalue(args.GetNextArg(), int);
return new R<int>(ref i);
}
static R<int> F2()
{
int i = 2;
return F1(__arglist(ref i));
}
}";
var comp = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.Regular10);
comp.VerifyEmitDiagnostics();
comp = CreateCompilationWithMscorlib45(source);
comp.VerifyEmitDiagnostics(
// (12,16): error CS8347: Cannot use a result of 'R<int>.R(ref int)' in this context because it may expose variables referenced by parameter 't' outside of their declaration scope
// return new R<int>(ref i);
Diagnostic(ErrorCode.ERR_EscapeCall, "new R<int>(ref i)").WithArguments("R<int>.R(ref int)", "t").WithLocation(12, 16),
// (12,31): error CS8157: Cannot return 'i' by reference because it was initialized to a value that cannot be returned by reference
// return new R<int>(ref i);
Diagnostic(ErrorCode.ERR_RefReturnNonreturnableLocal, "i").WithArguments("i").WithLocation(12, 31));
}
[Fact]
public void ImplicitIn_01()
{
var source =
@"ref struct R<T>
{
public void F(in T t) { }
}
class Program
{
static R<int> F1()
{
var r1 = new R<int>();
int i = 1;
r1.F(in i);
return r1;
}
static R<int> F2()
{
var r2 = new R<int>();
int i = 2;
r2.F(i);
return r2;
}
static R<int> F3()
{
var r3 = new R<int>();
r3.F(3);
return r3;
}
}";
var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10);
comp.VerifyEmitDiagnostics();
comp = CreateCompilation(source);
comp.VerifyEmitDiagnostics();
}
[Theory]
[InlineData(LanguageVersion.CSharp10)]
[InlineData(LanguageVersion.CSharp11)]
public void ImplicitIn_02(LanguageVersion languageVersion)
{
var source =
@"class Program
{
static ref readonly T F<T>(in T t)
{
return ref t;
}
static ref readonly int F1()
{
int i1 = 1;
return ref F(in i1); // 1
}
static ref readonly int F2()
{
int i2 = 2;
return ref F(i2); // 2
}
static ref readonly int F3()
{
return ref F(3); // 3
}
}";
var comp = CreateCompilation(source, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion));
comp.VerifyEmitDiagnostics(
// (10,20): error CS8347: Cannot use a result of 'Program.F<int>(in int)' in this context because it may expose variables referenced by parameter 't' outside of their declaration scope
// return ref F(in i1); // 1
Diagnostic(ErrorCode.ERR_EscapeCall, "F(in i1)").WithArguments("Program.F<int>(in int)", "t").WithLocation(10, 20),
// (10,25): error CS8168: Cannot return local 'i1' by reference because it is not a ref local
// return ref F(in i1); // 1
Diagnostic(ErrorCode.ERR_RefReturnLocal, "i1").WithArguments("i1").WithLocation(10, 25),
// (15,20): error CS8347: Cannot use a result of 'Program.F<int>(in int)' in this context because it may expose variables referenced by parameter 't' outside of their declaration scope
// return ref F(i2); // 2
Diagnostic(ErrorCode.ERR_EscapeCall, "F(i2)").WithArguments("Program.F<int>(in int)", "t").WithLocation(15, 20),
// (15,22): error CS8168: Cannot return local 'i2' by reference because it is not a ref local
// return ref F(i2); // 2
Diagnostic(ErrorCode.ERR_RefReturnLocal, "i2").WithArguments("i2").WithLocation(15, 22),
// (19,20): error CS8347: Cannot use a result of 'Program.F<int>(in int)' in this context because it may expose variables referenced by parameter 't' outside of their declaration scope
// return ref F(3); // 3
Diagnostic(ErrorCode.ERR_EscapeCall, "F(3)").WithArguments("Program.F<int>(in int)", "t").WithLocation(19, 20),
// (19,22): error CS8156: An expression cannot be used in this context because it may not be passed or returned by reference
// return ref F(3); // 3
Diagnostic(ErrorCode.ERR_RefReturnLvalueExpected, "3").WithLocation(19, 22));
}
[Fact]
public void ImplicitIn_03()
{
var source =
@"class Program
{
static ref readonly T F<T>(in T x, scoped in T y)
{
return ref x;
}
static ref readonly int F1()
{
int x1 = 1;
int y1 = 1;
return ref F(in x1, in y1); // 1
}
static ref readonly int F2()
{
int x2 = 2;
int y2 = 2;
return ref F(x2, in y2); // 2
}
static ref readonly int F3()
{
int y3 = 3;
return ref F(3, in y3); // 3
}
}";
var comp = CreateCompilation(source);
comp.VerifyEmitDiagnostics(
// (11,20): error CS8347: Cannot use a result of 'Program.F<int>(in int, scoped in int)' in this context because it may expose variables referenced by parameter 'x' outside of their declaration scope
// return ref F(in x1, in y1); // 1
Diagnostic(ErrorCode.ERR_EscapeCall, "F(in x1, in y1)").WithArguments("Program.F<int>(in int, scoped in int)", "x").WithLocation(11, 20),
// (11,25): error CS8168: Cannot return local 'x1' by reference because it is not a ref local
// return ref F(in x1, in y1); // 1
Diagnostic(ErrorCode.ERR_RefReturnLocal, "x1").WithArguments("x1").WithLocation(11, 25),
// (17,20): error CS8347: Cannot use a result of 'Program.F<int>(in int, scoped in int)' in this context because it may expose variables referenced by parameter 'x' outside of their declaration scope
// return ref F(x2, in y2); // 2
Diagnostic(ErrorCode.ERR_EscapeCall, "F(x2, in y2)").WithArguments("Program.F<int>(in int, scoped in int)", "x").WithLocation(17, 20),
// (17,22): error CS8168: Cannot return local 'x2' by reference because it is not a ref local
// return ref F(x2, in y2); // 2
Diagnostic(ErrorCode.ERR_RefReturnLocal, "x2").WithArguments("x2").WithLocation(17, 22),
// (22,20): error CS8347: Cannot use a result of 'Program.F<int>(in int, scoped in int)' in this context because it may expose variables referenced by parameter 'x' outside of their declaration scope
// return ref F(3, in y3); // 3
Diagnostic(ErrorCode.ERR_EscapeCall, "F(3, in y3)").WithArguments("Program.F<int>(in int, scoped in int)", "x").WithLocation(22, 20),
// (22,22): error CS8156: An expression cannot be used in this context because it may not be passed or returned by reference
// return ref F(3, in y3); // 3
Diagnostic(ErrorCode.ERR_RefReturnLvalueExpected, "3").WithLocation(22, 22));
}
[Fact]
public void RefToRefStruct_InstanceMethods()
{
var source =
@"using System.Diagnostics.CodeAnalysis;
ref struct R
{
public R(ref R other) { }
public void F1(ref R other) { }
[UnscopedRef] public void F2(ref R other) { }
}
class Program
{
static R F0()
{
var x0 = new R();
var y0 = new R(ref x0);
return x0;
}
static R F1()
{
var x1 = new R();
var y1 = new R();
y1.F1(ref x1);
return x1;
}
static R F2()
{
var x2 = new R();
var y2 = new R();
y2.F2(ref x2);
return x2;
}
}";
var comp = CreateCompilation(new[] { source, UnscopedRefAttributeDefinition });
comp.VerifyEmitDiagnostics();
}
[Fact]
public void RefToRefStruct_ConstructorInitializer()
{
var source =
@"ref struct R
{
public R(ref R other) { }
public R(ref R other, int i) :
this(ref other)
{
}
}";
var comp = CreateCompilation(source);
comp.VerifyEmitDiagnostics();
}
[Fact]
public void NestedFieldAccessor()
{
var source =
@"ref struct R<T>
{
private ref T _t;
public R(ref T t) { _t = t; }
public ref T F0() => ref _t;
ref T F1() => ref F0();
}
class Program
{
static ref T F2<T>(ref R<T> r) => ref r.F0();
}";
var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70);
comp.VerifyEmitDiagnostics();
}
[Fact]
public void Constructors()
{
var source =
@"ref struct S<T>
{
public ref T F;
public S(ref T t)
{
F = ref t;
}
S(object unused, T t0)
{
this = default;
this = new S<T>();
this = new S<T>(ref t0);
this = new S<T> { F = t0 };
}
void M1(T t1)
{
this = default;
this = new S<T>();
this = new S<T>(ref t1);
this = new S<T> { F = t1 };
}
static void M2(T t2)
{
S<T> s2;
s2 = default;
s2 = new S<T>();
s2 = new S<T>(ref t2);
s2 = new S<T> { F = t2 };
}
static void M3(ref T t3)
{
scoped S<T> s3;
s3 = new S<T>(ref t3);
s3 = new S<T> { F = t3 };
}
static void M4(T t4)
{
S<T> s;
s = new S<T>();
s = new S<T>(ref t4);
s = new S<T> { F = t4 };
}
}";
var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70);
comp.VerifyEmitDiagnostics(
// (12,16): error CS8347: Cannot use a result of 'S<T>.S(ref T)' in this context because it may expose variables referenced by parameter 't' outside of their declaration scope
// this = new S<T>(ref t0);
Diagnostic(ErrorCode.ERR_EscapeCall, "new S<T>(ref t0)").WithArguments("S<T>.S(ref T)", "t").WithLocation(12, 16),
// (12,29): error CS8166: Cannot return a parameter by reference 't0' because it is not a ref parameter
// this = new S<T>(ref t0);
Diagnostic(ErrorCode.ERR_RefReturnParameter, "t0").WithArguments("t0").WithLocation(12, 29),
// (19,16): error CS8347: Cannot use a result of 'S<T>.S(ref T)' in this context because it may expose variables referenced by parameter 't' outside of their declaration scope
// this = new S<T>(ref t1);
Diagnostic(ErrorCode.ERR_EscapeCall, "new S<T>(ref t1)").WithArguments("S<T>.S(ref T)", "t").WithLocation(19, 16),
// (19,29): error CS8166: Cannot return a parameter by reference 't1' because it is not a ref parameter
// this = new S<T>(ref t1);
Diagnostic(ErrorCode.ERR_RefReturnParameter, "t1").WithArguments("t1").WithLocation(19, 29),
// (27,14): error CS8347: Cannot use a result of 'S<T>.S(ref T)' in this context because it may expose variables referenced by parameter 't' outside of their declaration scope
// s2 = new S<T>(ref t2);
Diagnostic(ErrorCode.ERR_EscapeCall, "new S<T>(ref t2)").WithArguments("S<T>.S(ref T)", "t").WithLocation(27, 14),
// (27,27): error CS8166: Cannot return a parameter by reference 't2' because it is not a ref parameter
// s2 = new S<T>(ref t2);
Diagnostic(ErrorCode.ERR_RefReturnParameter, "t2").WithArguments("t2").WithLocation(27, 27),
// (40,13): error CS8347: Cannot use a result of 'S<T>.S(ref T)' in this context because it may expose variables referenced by parameter 't' outside of their declaration scope
// s = new S<T>(ref t4);
Diagnostic(ErrorCode.ERR_EscapeCall, "new S<T>(ref t4)").WithArguments("S<T>.S(ref T)", "t").WithLocation(40, 13),
// (40,26): error CS8166: Cannot return a parameter by reference 't4' because it is not a ref parameter
// s = new S<T>(ref t4);
Diagnostic(ErrorCode.ERR_RefReturnParameter, "t4").WithArguments("t4").WithLocation(40, 26));
}
[Fact]
public void Constructors_UnsafeContext()
{
var source = @"
unsafe ref struct S<T>
{
public ref T F;
public S(ref T t)
{
F = ref t;
}
S(object unused, T t0)
{
this = default;
this = new S<T>();
this = new S<T>(ref t0);
this = new S<T> { F = t0 };
}
void M1(T t1)
{
this = default;
this = new S<T>();
this = new S<T>(ref t1);
this = new S<T> { F = t1 };
}
static void M2(T t2)
{
S<T> s2;
s2 = default;
s2 = new S<T>();
s2 = new S<T>(ref t2);
s2 = new S<T> { F = t2 };
}
static void M3(ref T t3)
{
scoped S<T> s3;
s3 = new S<T>(ref t3);
s3 = new S<T> { F = t3 };
}
static void M4(T t4)
{
S<T> s;
s = new S<T>();
s = new S<T>(ref t4);
s = new S<T> { F = t4 };
}
}";
var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70, options: TestOptions.UnsafeDebugDll);
comp.VerifyEmitDiagnostics(
// (13,29): warning CS9084: This returns a parameter by reference 't0' but it is not a ref parameter
// this = new S<T>(ref t0);
Diagnostic(ErrorCode.WRN_RefReturnParameter, "t0").WithArguments("t0").WithLocation(13, 29),
// (20,29): warning CS9084: This returns a parameter by reference 't1' but it is not a ref parameter
// this = new S<T>(ref t1);
Diagnostic(ErrorCode.WRN_RefReturnParameter, "t1").WithArguments("t1").WithLocation(20, 29),
// (28,27): warning CS9084: This returns a parameter by reference 't2' but it is not a ref parameter
// s2 = new S<T>(ref t2);
Diagnostic(ErrorCode.WRN_RefReturnParameter, "t2").WithArguments("t2").WithLocation(28, 27),
// (41,26): warning CS9084: This returns a parameter by reference 't4' but it is not a ref parameter
// s = new S<T>(ref t4);
Diagnostic(ErrorCode.WRN_RefReturnParameter, "t4").WithArguments("t4").WithLocation(41, 26));
}
[Fact]
public void Constructors_02()
{
var source = """
ref struct R
{
public R(ref int i) { }
public int this[R r] { get { return 0; } set { } }
}
class Program
{
static R F()
{
int i = 0;
R x = new R(ref i);
R y = default;
y = new R { [x] = 1 }; // 1
y[x] = 1; // 2
return y;
}
}
""";
var comp = CreateCompilation(source);
comp.VerifyDiagnostics(
// (13,22): error CS8352: Cannot use variable 'x' in this context because it may expose referenced variables outside of their declaration scope
// y = new R { [x] = 1 }; // 1
Diagnostic(ErrorCode.ERR_EscapeVariable, "x").WithArguments("x").WithLocation(13, 22),
// (14,9): error CS8350: This combination of arguments to 'R.this[R]' is disallowed because it may expose variables referenced by parameter 'r' outside of their declaration scope
// y[x] = 1; // 2
Diagnostic(ErrorCode.ERR_CallArgMixing, "y[x]").WithArguments("R.this[R]", "r").WithLocation(14, 9),
// (14,11): error CS8352: Cannot use variable 'x' in this context because it may expose referenced variables outside of their declaration scope
// y[x] = 1; // 2
Diagnostic(ErrorCode.ERR_EscapeVariable, "x").WithArguments("x").WithLocation(14, 11));
}
[Fact]
public void DefiniteAssignment_01()
{
var source =
@"ref struct S1<T>
{
public ref T F;
}
ref struct S2<T>
{
public ref T F;
public S2(ref T t) { }
}
ref struct S3<T>
{
public ref T F;
public S3(ref T t) : this() { }
}
ref struct S4<T>
{
public ref T F;
public S4(ref T t)
{
this = default;
}
}
class Program
{
static void F<T>(ref T t)
{
new S1<T>().F = ref t;
new S2<T>().F = ref t;
new S3<T>().F = ref t;
new S4<T>().F = ref t;
new S1<T>().F = t;
new S2<T>().F = t;
new S3<T>().F = t;
new S4<T>().F = t;
}
}";
var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70);
comp.VerifyEmitDiagnostics(
// (27,9): error CS0131: The left-hand side of an assignment must be a variable, property or indexer
// new S1<T>().F = ref t;
Diagnostic(ErrorCode.ERR_AssgLvalueExpected, "new S1<T>().F").WithLocation(27, 9),
// (28,9): error CS0131: The left-hand side of an assignment must be a variable, property or indexer
// new S2<T>().F = ref t;
Diagnostic(ErrorCode.ERR_AssgLvalueExpected, "new S2<T>().F").WithLocation(28, 9),
// (29,9): error CS0131: The left-hand side of an assignment must be a variable, property or indexer
// new S3<T>().F = ref t;
Diagnostic(ErrorCode.ERR_AssgLvalueExpected, "new S3<T>().F").WithLocation(29, 9),
// (30,9): error CS0131: The left-hand side of an assignment must be a variable, property or indexer
// new S4<T>().F = ref t;
Diagnostic(ErrorCode.ERR_AssgLvalueExpected, "new S4<T>().F").WithLocation(30, 9));
}
[Fact]
public void DefiniteAssignment_02()
{
// Should we report a warning when assigning a value rather than a ref in the
// constructor, because a NullReferenceException will be thrown at runtime?
var source =
@"ref struct S<T>
{
public ref T F;
public S(ref T t)
{
F = t;
}
}";
var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70);
comp.VerifyEmitDiagnostics();
}
[Fact]
public void AssignLocal()
{
var source =
@"ref struct S<T>
{
public ref T F1;
public ref readonly T F2;
public readonly ref T F3;
public readonly ref readonly T F4;
public S()
{
T t = default;
F1 = ref t;
F2 = ref t;
F3 = ref t;
F4 = ref t;
}
}
class Program
{
static void M<T>(ref S<T> x)
{
T t = default;
x.F1 = ref t;
x.F2 = ref t;
x.F3 = ref t;
x.F4 = ref t;
S<T> y = new S<T>();
y.F1 = ref t;
y.F2 = ref t;
y.F3 = ref t;
y.F4 = ref t;
}
}";
var comp = CreateCompilation(new[] { source, IsExternalInitTypeDefinition }, targetFramework: TargetFramework.Net70);
comp.VerifyEmitDiagnostics(
// (10,9): error CS8374: Cannot ref-assign 't' to 'F1' because 't' has a narrower escape scope than 'F1'.
// F1 = ref t;
Diagnostic(ErrorCode.ERR_RefAssignNarrower, "F1 = ref t").WithArguments("F1", "t").WithLocation(10, 9),
// (11,9): error CS8374: Cannot ref-assign 't' to 'F2' because 't' has a narrower escape scope than 'F2'.
// F2 = ref t;
Diagnostic(ErrorCode.ERR_RefAssignNarrower, "F2 = ref t").WithArguments("F2", "t").WithLocation(11, 9),
// (12,9): error CS8374: Cannot ref-assign 't' to 'F3' because 't' has a narrower escape scope than 'F3'.
// F3 = ref t;
Diagnostic(ErrorCode.ERR_RefAssignNarrower, "F3 = ref t").WithArguments("F3", "t").WithLocation(12, 9),
// (13,9): error CS8374: Cannot ref-assign 't' to 'F4' because 't' has a narrower escape scope than 'F4'.
// F4 = ref t;
Diagnostic(ErrorCode.ERR_RefAssignNarrower, "F4 = ref t").WithArguments("F4", "t").WithLocation(13, 9),
// (21,9): error CS8374: Cannot ref-assign 't' to 'F1' because 't' has a narrower escape scope than 'F1'.
// x.F1 = ref t;
Diagnostic(ErrorCode.ERR_RefAssignNarrower, "x.F1 = ref t").WithArguments("F1", "t").WithLocation(21, 9),
// (22,9): error CS8374: Cannot ref-assign 't' to 'F2' because 't' has a narrower escape scope than 'F2'.
// x.F2 = ref t;
Diagnostic(ErrorCode.ERR_RefAssignNarrower, "x.F2 = ref t").WithArguments("F2", "t").WithLocation(22, 9),
// (23,9): 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)
// x.F3 = ref t;
Diagnostic(ErrorCode.ERR_AssgReadonly, "x.F3").WithLocation(23, 9),
// (24,9): 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)
// x.F4 = ref t;
Diagnostic(ErrorCode.ERR_AssgReadonly, "x.F4").WithLocation(24, 9),
// (26,9): error CS8374: Cannot ref-assign 't' to 'F1' because 't' has a narrower escape scope than 'F1'.
// y.F1 = ref t;
Diagnostic(ErrorCode.ERR_RefAssignNarrower, "y.F1 = ref t").WithArguments("F1", "t").WithLocation(26, 9),
// (27,9): error CS8374: Cannot ref-assign 't' to 'F2' because 't' has a narrower escape scope than 'F2'.
// y.F2 = ref t;
Diagnostic(ErrorCode.ERR_RefAssignNarrower, "y.F2 = ref t").WithArguments("F2", "t").WithLocation(27, 9),
// (28,9): 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)
// y.F3 = ref t;
Diagnostic(ErrorCode.ERR_AssgReadonly, "y.F3").WithLocation(28, 9),
// (29,9): 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)
// y.F4 = ref t;
Diagnostic(ErrorCode.ERR_AssgReadonly, "y.F4").WithLocation(29, 9));
}
[Fact]
public void AssignValueTo_InstanceMethod_RefField()
{
var source =
@"ref struct S<T>
{
public ref T F;
public S(T tValue, ref T tRef, out T tOut, in T tIn)
{
tOut = default;
F = tValue;
F = tRef;
F = tOut;
F = tIn;
}
object P
{
init
{
F = GetValue();
F = GetRef();
F = GetRefReadonly();
}
}
static T GetValue() => throw null;
static ref T GetRef() => throw null;
static ref readonly T GetRefReadonly() => throw null;
}";
var comp = CreateCompilation(new[] { source, IsExternalInitTypeDefinition }, targetFramework: TargetFramework.Net70);
comp.VerifyEmitDiagnostics();
}
[Fact]
public void AssignValueTo_InstanceMethod_RefReadonlyField()
{
var source =
@"ref struct S<T>
{
public ref readonly T F;
public S(T tValue, ref T tRef, out T tOut, in T tIn)
{
tOut = default;
F = tValue; // 1
F = tRef; // 2
F = tOut; // 3
F = tIn; // 4
}
object P
{
init
{
F = GetValue(); // 5
F = GetRef(); // 6
F = GetRefReadonly(); // 7
}
}
static T GetValue() => throw null;
static ref T GetRef() => throw null;
static ref readonly T GetRefReadonly() => throw null;
}";
var comp = CreateCompilation(new[] { source, IsExternalInitTypeDefinition }, targetFramework: TargetFramework.Net70);
comp.VerifyEmitDiagnostics(
// (7,9): error CS8331: Cannot assign to field 'F' or use it as the right hand side of a ref assignment because it is a readonly variable
// F = tValue; // 1
Diagnostic(ErrorCode.ERR_AssignReadonlyNotField, "F").WithArguments("field", "F").WithLocation(7, 9),
// (8,9): error CS8331: Cannot assign to field 'F' or use it as the right hand side of a ref assignment because it is a readonly variable
// F = tRef; // 2
Diagnostic(ErrorCode.ERR_AssignReadonlyNotField, "F").WithArguments("field", "F").WithLocation(8, 9),
// (9,9): error CS8331: Cannot assign to field 'F' or use it as the right hand side of a ref assignment because it is a readonly variable
// F = tOut; // 3
Diagnostic(ErrorCode.ERR_AssignReadonlyNotField, "F").WithArguments("field", "F").WithLocation(9, 9),
// (10,9): error CS8331: Cannot assign to field 'F' or use it as the right hand side of a ref assignment because it is a readonly variable
// F = tIn; // 4
Diagnostic(ErrorCode.ERR_AssignReadonlyNotField, "F").WithArguments("field", "F").WithLocation(10, 9),
// (16,13): error CS8331: Cannot assign to field 'F' or use it as the right hand side of a ref assignment because it is a readonly variable
// F = GetValue(); // 5
Diagnostic(ErrorCode.ERR_AssignReadonlyNotField, "F").WithArguments("field", "F").WithLocation(16, 13),
// (17,13): error CS8331: Cannot assign to field 'F' or use it as the right hand side of a ref assignment because it is a readonly variable
// F = GetRef(); // 6
Diagnostic(ErrorCode.ERR_AssignReadonlyNotField, "F").WithArguments("field", "F").WithLocation(17, 13),
// (18,13): error CS8331: Cannot assign to field 'F' or use it as the right hand side of a ref assignment because it is a readonly variable
// F = GetRefReadonly(); // 7
Diagnostic(ErrorCode.ERR_AssignReadonlyNotField, "F").WithArguments("field", "F").WithLocation(18, 13));
}
[Fact]
public void AssignValueTo_InstanceMethod_ReadonlyRefField()
{
var source =
@"ref struct S<T>
{
public readonly ref T F;
public S(T tValue, ref T tRef, out T tOut, in T tIn)
{
tOut = default;
F = tValue;
F = tRef;
F = tOut;
F = tIn;
}
object P
{
init
{
F = GetValue();
F = GetRef();
F = GetRefReadonly();
}
}
static T GetValue() => throw null;
static ref T GetRef() => throw null;
static ref readonly T GetRefReadonly() => throw null;
}";
var comp = CreateCompilation(new[] { source, IsExternalInitTypeDefinition }, targetFramework: TargetFramework.Net70);
comp.VerifyEmitDiagnostics();
}
[Fact]
public void AssignValueTo_InstanceMethod_ReadonlyRefReadonlyField()
{
var source =
@"ref struct S<T>
{
public readonly ref readonly T F;
public S(T tValue, ref T tRef, out T tOut, in T tIn)
{
tOut = default;
F = tValue; // 1
F = tRef; // 2
F = tOut; // 3
F = tIn; // 4
}
object P
{
init
{
F = GetValue(); // 5
F = GetRef(); // 6
F = GetRefReadonly(); // 7
}
}
static T GetValue() => throw null;
static ref T GetRef() => throw null;
static ref readonly T GetRefReadonly() => throw null;
}";
var comp = CreateCompilation(new[] { source, IsExternalInitTypeDefinition }, targetFramework: TargetFramework.Net70);
comp.VerifyEmitDiagnostics(
// (7,9): error CS8331: Cannot assign to field 'F' or use it as the right hand side of a ref assignment because it is a readonly variable
// F = tValue; // 1
Diagnostic(ErrorCode.ERR_AssignReadonlyNotField, "F").WithArguments("field", "F").WithLocation(7, 9),
// (8,9): error CS8331: Cannot assign to field 'F' or use it as the right hand side of a ref assignment because it is a readonly variable
// F = tRef; // 2
Diagnostic(ErrorCode.ERR_AssignReadonlyNotField, "F").WithArguments("field", "F").WithLocation(8, 9),
// (9,9): error CS8331: Cannot assign to field 'F' or use it as the right hand side of a ref assignment because it is a readonly variable
// F = tOut; // 3
Diagnostic(ErrorCode.ERR_AssignReadonlyNotField, "F").WithArguments("field", "F").WithLocation(9, 9),
// (10,9): error CS8331: Cannot assign to field 'F' or use it as the right hand side of a ref assignment because it is a readonly variable
// F = tIn; // 4
Diagnostic(ErrorCode.ERR_AssignReadonlyNotField, "F").WithArguments("field", "F").WithLocation(10, 9),
// (16,13): error CS8331: Cannot assign to field 'F' or use it as the right hand side of a ref assignment because it is a readonly variable
// F = GetValue(); // 5
Diagnostic(ErrorCode.ERR_AssignReadonlyNotField, "F").WithArguments("field", "F").WithLocation(16, 13),
// (17,13): error CS8331: Cannot assign to field 'F' or use it as the right hand side of a ref assignment because it is a readonly variable
// F = GetRef(); // 6
Diagnostic(ErrorCode.ERR_AssignReadonlyNotField, "F").WithArguments("field", "F").WithLocation(17, 13),
// (18,13): error CS8331: Cannot assign to field 'F' or use it as the right hand side of a ref assignment because it is a readonly variable
// F = GetRefReadonly(); // 7
Diagnostic(ErrorCode.ERR_AssignReadonlyNotField, "F").WithArguments("field", "F").WithLocation(18, 13));
}
[Fact]
public void AssignRefTo_InstanceMethod_RefField()
{
var source =
@"ref struct S<T>
{
public ref T F;
public S(T tValue, ref T tRef, out T tOut, in T tIn)
{
tOut = default;
F = ref tValue; // 1
F = ref tRef;
F = ref tOut; // 2
F = ref tIn; // 3
}
T P
{
init
{
F = ref value; // 4
F = ref GetRef();
F = ref GetRefReadonly(); // 5
}
}
static ref T GetRef() => throw null;
static ref readonly T GetRefReadonly() => throw null;
}";
var comp = CreateCompilation(new[] { source, IsExternalInitTypeDefinition }, targetFramework: TargetFramework.Net70);
comp.VerifyEmitDiagnostics(
// (7,9): error CS8374: Cannot ref-assign 'tValue' to 'F' because 'tValue' has a narrower escape scope than 'F'.
// F = ref tValue; // 1
Diagnostic(ErrorCode.ERR_RefAssignNarrower, "F = ref tValue").WithArguments("F", "tValue").WithLocation(7, 9),
// (9,9): error CS8374: Cannot ref-assign 'tOut' to 'F' because 'tOut' has a narrower escape scope than 'F'.
// F = ref tOut; // 2
Diagnostic(ErrorCode.ERR_RefAssignNarrower, "F = ref tOut").WithArguments("F", "tOut").WithLocation(9, 9),
// (10,17): error CS8331: Cannot assign to variable 'tIn' or use it as the right hand side of a ref assignment because it is a readonly variable
// F = ref tIn; // 3
Diagnostic(ErrorCode.ERR_AssignReadonlyNotField, "tIn").WithArguments("variable", "tIn").WithLocation(10, 17),
// (16,13): error CS8374: Cannot ref-assign 'value' to 'F' because 'value' has a narrower escape scope than 'F'.
// F = ref value; // 4
Diagnostic(ErrorCode.ERR_RefAssignNarrower, "F = ref value").WithArguments("F", "value").WithLocation(16, 13),
// (18,21): error CS8331: Cannot assign to method 'GetRefReadonly' or use it as the right hand side of a ref assignment because it is a readonly variable
// F = ref GetRefReadonly(); // 5
Diagnostic(ErrorCode.ERR_AssignReadonlyNotField, "GetRefReadonly()").WithArguments("method", "GetRefReadonly").WithLocation(18, 21));
}
[Fact]
public void AssignRefTo_InstanceMethod_RefReadonlyField()
{
var source =
@"ref struct S<T>
{
public ref readonly T F;
public S(T tValue, ref T tRef, out T tOut, in T tIn)
{
tOut = default;
F = ref tValue; // 1
F = ref tRef;
F = ref tOut; // 2
F = ref tIn;
}
T P
{
init
{
F = ref value; // 3
F = ref GetRef();
F = ref GetRefReadonly();
}
}
static ref T GetRef() => throw null;
static ref readonly T GetRefReadonly() => throw null;
}";
var comp = CreateCompilation(new[] { source, IsExternalInitTypeDefinition }, targetFramework: TargetFramework.Net70);
comp.VerifyEmitDiagnostics(
// (7,9): error CS8374: Cannot ref-assign 'tValue' to 'F' because 'tValue' has a narrower escape scope than 'F'.
// F = ref tValue; // 1
Diagnostic(ErrorCode.ERR_RefAssignNarrower, "F = ref tValue").WithArguments("F", "tValue").WithLocation(7, 9),
// (9,9): error CS8374: Cannot ref-assign 'tOut' to 'F' because 'tOut' has a narrower escape scope than 'F'.
// F = ref tOut; // 2
Diagnostic(ErrorCode.ERR_RefAssignNarrower, "F = ref tOut").WithArguments("F", "tOut").WithLocation(9, 9),
// (16,13): error CS8374: Cannot ref-assign 'value' to 'F' because 'value' has a narrower escape scope than 'F'.
// F = ref value; // 3
Diagnostic(ErrorCode.ERR_RefAssignNarrower, "F = ref value").WithArguments("F", "value").WithLocation(16, 13));
}
[Fact]
public void AssignRefTo_InstanceMethod_ReadonlyRefField()
{
var source =
@"ref struct S<T>
{
public readonly ref T F;
public S(T tValue, ref T tRef, out T tOut, in T tIn)
{
tOut = default;
F = ref tValue; // 1
F = ref tRef;
F = ref tOut; // 2
F = ref tIn; // 3
}
T P
{
init
{
F = ref value; // 4
F = ref GetRef();
F = ref GetRefReadonly(); // 5
}
}
static ref T GetRef() => throw null;
static ref readonly T GetRefReadonly() => throw null;
}";
var comp = CreateCompilation(new[] { source, IsExternalInitTypeDefinition }, targetFramework: TargetFramework.Net70);
comp.VerifyEmitDiagnostics(
// (7,9): error CS8374: Cannot ref-assign 'tValue' to 'F' because 'tValue' has a narrower escape scope than 'F'.
// F = ref tValue; // 1
Diagnostic(ErrorCode.ERR_RefAssignNarrower, "F = ref tValue").WithArguments("F", "tValue").WithLocation(7, 9),
// (9,9): error CS8374: Cannot ref-assign 'tOut' to 'F' because 'tOut' has a narrower escape scope than 'F'.
// F = ref tOut; // 2
Diagnostic(ErrorCode.ERR_RefAssignNarrower, "F = ref tOut").WithArguments("F", "tOut").WithLocation(9, 9),
// (10,17): error CS8331: Cannot assign to variable 'tIn' or use it as the right hand side of a ref assignment because it is a readonly variable
// F = ref tIn; // 3
Diagnostic(ErrorCode.ERR_AssignReadonlyNotField, "tIn").WithArguments("variable", "tIn").WithLocation(10, 17),
// (16,13): error CS8374: Cannot ref-assign 'value' to 'F' because 'value' has a narrower escape scope than 'F'.
// F = ref value; // 4
Diagnostic(ErrorCode.ERR_RefAssignNarrower, "F = ref value").WithArguments("F", "value").WithLocation(16, 13),
// (18,21): error CS8331: Cannot assign to method 'GetRefReadonly' or use it as the right hand side of a ref assignment because it is a readonly variable
// F = ref GetRefReadonly(); // 5
Diagnostic(ErrorCode.ERR_AssignReadonlyNotField, "GetRefReadonly()").WithArguments("method", "GetRefReadonly").WithLocation(18, 21));
}
[Fact]
public void AssignRefTo_InstanceMethod_ReadonlyRefReadonlyField()
{
var source =
@"ref struct S<T>
{
public readonly ref readonly T F;
public S(T tValue, ref T tRef, out T tOut, in T tIn)
{
tOut = default;
F = ref tValue; // 1
F = ref tRef;
F = ref tOut; // 2
F = ref tIn;
}
T P
{
init
{
F = ref value; // 3
F = ref GetRef();
F = ref GetRefReadonly();
}
}
static ref T GetRef() => throw null;
static ref readonly T GetRefReadonly() => throw null;
}";
var comp = CreateCompilation(new[] { source, IsExternalInitTypeDefinition }, targetFramework: TargetFramework.Net70);
comp.VerifyEmitDiagnostics(
// (7,9): error CS8374: Cannot ref-assign 'tValue' to 'F' because 'tValue' has a narrower escape scope than 'F'.
// F = ref tValue; // 1
Diagnostic(ErrorCode.ERR_RefAssignNarrower, "F = ref tValue").WithArguments("F", "tValue").WithLocation(7, 9),
// (9,9): error CS8374: Cannot ref-assign 'tOut' to 'F' because 'tOut' has a narrower escape scope than 'F'.
// F = ref tOut; // 2
Diagnostic(ErrorCode.ERR_RefAssignNarrower, "F = ref tOut").WithArguments("F", "tOut").WithLocation(9, 9),
// (16,13): error CS8374: Cannot ref-assign 'value' to 'F' because 'value' has a narrower escape scope than 'F'.
// F = ref value; // 3
Diagnostic(ErrorCode.ERR_RefAssignNarrower, "F = ref value").WithArguments("F", "value").WithLocation(16, 13));
}
[Fact]
public void AssignValueTo_RefField()
{
var source =
@"using System;
ref struct S<T>
{
public ref T F;
public S(ref T t) { F = ref t; }
}
class Program
{
static void AssignValueToValue<T>(S<T> s, T tValue) { s.F = tValue; }
static void AssignRefToValue<T>(S<T> s, ref T tRef) { s.F = tRef; }
static void AssignOutToValue<T>(S<T> s, out T tOut) { tOut = default; s.F = tOut; }
static void AssignInToValue<T>(S<T> s, in T tIn) { s.F = tIn; }
static void AssignValueToRef<T>(ref S<T> sRef, T tValue) { sRef.F = tValue; }
static void AssignRefToRef<T>(ref S<T> sRef, ref T tRef) { sRef.F = tRef; }
static void AssignOutToRef<T>(ref S<T> sRef, out T tOut) { tOut = default; sRef.F = tOut; }
static void AssignInToRef<T>(ref S<T> sRef, in T tIn) { sRef.F = tIn; }
static void AssignValueToOut<T>(out S<T> sOut, S<T> sInit, T tValue) { sOut = sInit; sOut.F = tValue; }
static void AssignRefToOut<T>(out S<T> sOut, S<T> sInit, ref T tRef) { sOut = sInit; sOut.F = tRef; }
static void AssignOutToOut<T>(out S<T> sOut, S<T> sInit, out T tOut) { sOut = sInit; tOut = default; sOut.F = tOut; }
static void AssignInToOut<T>(out S<T> sOut, S<T> sInit, in T tIn) { sOut = sInit; sOut.F = tIn; }
static void AssignValueToIn<T>(in S<T> sIn, T tValue) { sIn.F = tValue; }
static void AssignRefToIn<T>(in S<T> sIn, ref T tRef) { sIn.F = tRef; }
static void AssignOutToIn<T>(in S<T> sIn, out T tOut) { tOut = default; sIn.F = tOut; }
static void AssignInToIn<T>(in S<T> sIn, in T tIn) { sIn.F = tIn; }
static void Main()
{
int x, y;
scoped S<int> s;
x = 1; y = 2;
s = new S<int>(ref x);
AssignValueToValue(s, y);
Console.WriteLine(s.F);
x = 1; y = 2;
s = new S<int>(ref x);
AssignRefToValue(s, ref y);
Console.WriteLine(s.F);
x = 1; y = 2;
s = new S<int>(ref x);
AssignOutToValue(s, out y);
Console.WriteLine(s.F);
x = 1; y = 2;
s = new S<int>(ref x);
AssignInToValue(s, y);
Console.WriteLine(s.F);
x = 3; y = 4;
s = new S<int>(ref x);
AssignValueToRef(ref s, y);
Console.WriteLine(s.F);
x = 3; y = 4;
s = new S<int>(ref x);
AssignRefToRef(ref s, ref y);
Console.WriteLine(s.F);
x = 3; y = 4;
s = new S<int>(ref x);
AssignOutToRef(ref s, out y);
Console.WriteLine(s.F);
x = 3; y = 4;
s = new S<int>(ref x);
AssignInToRef(ref s, y);
Console.WriteLine(s.F);
x = 5; y = 6;
s = new S<int>(ref x);
AssignValueToOut(out s, new S<int>(ref x), y);
Console.WriteLine(s.F);
x = 5; y = 6;
s = new S<int>(ref x);
AssignRefToOut(out s, new S<int>(ref x), ref y);
Console.WriteLine(s.F);
x = 5; y = 6;
s = new S<int>(ref x);
AssignOutToOut(out s, new S<int>(ref x), out y);
Console.WriteLine(s.F);
x = 5; y = 6;
s = new S<int>(ref x);
AssignInToOut(out s, new S<int>(ref x), y);
Console.WriteLine(s.F);
x = 7; y = 8;
s = new S<int>(ref x);
AssignValueToIn(s, y);
Console.WriteLine(s.F);
x = 7; y = 8;
s = new S<int>(ref x);
AssignRefToIn(s, ref y);
Console.WriteLine(s.F);
x = 7; y = 8;
s = new S<int>(ref x);
AssignOutToIn(s, out y);
Console.WriteLine(s.F);
x = 7; y = 8;
s = new S<int>(ref x);
AssignInToIn(s, y);
Console.WriteLine(s.F);
}
}";
var comp = CreateCompilation(source, options: TestOptions.ReleaseExe, targetFramework: TargetFramework.Net70);
var verifier = CompileAndVerify(comp, verify: Verification.Skipped, expectedOutput: IncludeExpectedOutput(
@"2
2
0
2
4
4
0
4
6
6
0
6
8
8
0
8"));
verifier.VerifyILMultiple(
"Program.AssignValueToValue<T>",
@"{
// Code size 13 (0xd)
.maxstack 2
IL_0000: ldarg.0
IL_0001: ldfld ""ref T S<T>.F""
IL_0006: ldarg.1
IL_0007: stobj ""T""
IL_000c: ret
}",
"Program.AssignRefToValue<T>",
@"{
// Code size 18 (0x12)
.maxstack 2
IL_0000: ldarg.0
IL_0001: ldfld ""ref T S<T>.F""
IL_0006: ldarg.1
IL_0007: ldobj ""T""
IL_000c: stobj ""T""
IL_0011: ret
}",
"Program.AssignOutToValue<T>",
@"{
// Code size 25 (0x19)
.maxstack 2
IL_0000: ldarg.1
IL_0001: initobj ""T""
IL_0007: ldarg.0
IL_0008: ldfld ""ref T S<T>.F""
IL_000d: ldarg.1
IL_000e: ldobj ""T""
IL_0013: stobj ""T""
IL_0018: ret
}",
"Program.AssignInToValue<T>",
@"{
// Code size 18 (0x12)
.maxstack 2
IL_0000: ldarg.0
IL_0001: ldfld ""ref T S<T>.F""
IL_0006: ldarg.1
IL_0007: ldobj ""T""
IL_000c: stobj ""T""
IL_0011: ret
}",
"Program.AssignValueToRef<T>",
@"{
// Code size 13 (0xd)
.maxstack 2
IL_0000: ldarg.0
IL_0001: ldfld ""ref T S<T>.F""
IL_0006: ldarg.1
IL_0007: stobj ""T""
IL_000c: ret
}",
"Program.AssignRefToRef<T>",
@"{
// Code size 18 (0x12)
.maxstack 2
IL_0000: ldarg.0
IL_0001: ldfld ""ref T S<T>.F""
IL_0006: ldarg.1
IL_0007: ldobj ""T""
IL_000c: stobj ""T""
IL_0011: ret
}",
"Program.AssignOutToRef<T>",
@"{
// Code size 25 (0x19)
.maxstack 2
IL_0000: ldarg.1
IL_0001: initobj ""T""
IL_0007: ldarg.0
IL_0008: ldfld ""ref T S<T>.F""
IL_000d: ldarg.1
IL_000e: ldobj ""T""
IL_0013: stobj ""T""
IL_0018: ret
}",
"Program.AssignInToRef<T>",
@"{
// Code size 18 (0x12)
.maxstack 2
IL_0000: ldarg.0
IL_0001: ldfld ""ref T S<T>.F""
IL_0006: ldarg.1
IL_0007: ldobj ""T""
IL_000c: stobj ""T""
IL_0011: ret
}",
"Program.AssignValueToOut<T>",
@"{
// Code size 20 (0x14)
.maxstack 2
IL_0000: ldarg.0
IL_0001: ldarg.1
IL_0002: stobj ""S<T>""
IL_0007: ldarg.0
IL_0008: ldfld ""ref T S<T>.F""
IL_000d: ldarg.2
IL_000e: stobj ""T""
IL_0013: ret
}",
"Program.AssignRefToOut<T>",
@"{
// Code size 25 (0x19)
.maxstack 2
IL_0000: ldarg.0
IL_0001: ldarg.1
IL_0002: stobj ""S<T>""
IL_0007: ldarg.0
IL_0008: ldfld ""ref T S<T>.F""
IL_000d: ldarg.2
IL_000e: ldobj ""T""
IL_0013: stobj ""T""
IL_0018: ret
}",
"Program.AssignOutToOut<T>",
@"{
// Code size 32 (0x20)
.maxstack 2
IL_0000: ldarg.0
IL_0001: ldarg.1
IL_0002: stobj ""S<T>""
IL_0007: ldarg.2
IL_0008: initobj ""T""
IL_000e: ldarg.0
IL_000f: ldfld ""ref T S<T>.F""
IL_0014: ldarg.2
IL_0015: ldobj ""T""
IL_001a: stobj ""T""
IL_001f: ret
}",
"Program.AssignInToOut<T>",
@"{
// Code size 25 (0x19)
.maxstack 2
IL_0000: ldarg.0
IL_0001: ldarg.1
IL_0002: stobj ""S<T>""
IL_0007: ldarg.0
IL_0008: ldfld ""ref T S<T>.F""
IL_000d: ldarg.2
IL_000e: ldobj ""T""
IL_0013: stobj ""T""
IL_0018: ret
}",
"Program.AssignValueToIn<T>",
@"{
// Code size 13 (0xd)
.maxstack 2
IL_0000: ldarg.0
IL_0001: ldfld ""ref T S<T>.F""
IL_0006: ldarg.1
IL_0007: stobj ""T""
IL_000c: ret
}",
"Program.AssignRefToIn<T>",
@"{
// Code size 18 (0x12)
.maxstack 2
IL_0000: ldarg.0
IL_0001: ldfld ""ref T S<T>.F""
IL_0006: ldarg.1
IL_0007: ldobj ""T""
IL_000c: stobj ""T""
IL_0011: ret
}",
"Program.AssignOutToIn<T>",
@"{
// Code size 25 (0x19)
.maxstack 2
IL_0000: ldarg.1
IL_0001: initobj ""T""
IL_0007: ldarg.0
IL_0008: ldfld ""ref T S<T>.F""
IL_000d: ldarg.1
IL_000e: ldobj ""T""
IL_0013: stobj ""T""
IL_0018: ret
}",
"Program.AssignInToIn<T>",
@"{
// Code size 18 (0x12)
.maxstack 2
IL_0000: ldarg.0
IL_0001: ldfld ""ref T S<T>.F""
IL_0006: ldarg.1
IL_0007: ldobj ""T""
IL_000c: stobj ""T""
IL_0011: ret
}");
}
[Fact]
public void AssignValueTo_RefReadonlyField()
{
var source =
@"ref struct S<T>
{
public ref readonly T F;
public S(ref T t) { F = ref t; }
}
class Program
{
static void AssignValueToValue<T>(S<T> s, T tValue) { s.F = tValue; } // 1
static void AssignRefToValue<T>(S<T> s, ref T tRef) { s.F = tRef; } // 2
static void AssignOutToValue<T>(S<T> s, out T tOut) { tOut = default; s.F = tOut; } // 3
static void AssignInToValue<T>(S<T> s, in T tIn) { s.F = tIn; } // 4
static void AssignValueToRef<T>(ref S<T> sRef, T tValue) { sRef.F = tValue; } // 5
static void AssignRefToRef<T>(ref S<T> sRef, ref T tRef) { sRef.F = tRef; } // 6
static void AssignOutToRef<T>(ref S<T> sRef, out T tOut) { tOut = default; sRef.F = tOut; } // 7
static void AssignInToRef<T>(ref S<T> sRef, in T tIn) { sRef.F = tIn; } // 8
static void AssignValueToOut<T>(out S<T> sOut, T tValue) { sOut = default; sOut.F = tValue; } // 9
static void AssignRefToOut<T>(out S<T> sOut, ref T tRef) { sOut = default; sOut.F = tRef; } // 10
static void AssignOutToOut<T>(out S<T> sOut, out T tOut) { sOut = default; tOut = default; sOut.F = tOut; } // 11
static void AssignInToOut<T>(out S<T> sOut, in T tIn) { sOut = default; sOut.F = tIn; } // 12
static void AssignValueToIn<T>(in S<T> sIn, T tValue) { sIn.F = tValue; } // 13
static void AssignRefToIn<T>(in S<T> sIn, ref T tRef) { sIn.F = tRef; } // 14
static void AssignOutToIn<T>(in S<T> sIn, out T tOut) { tOut = default; sIn.F = tOut; } // 15
static void AssignInToIn<T>(in S<T> sIn, in T tIn) { sIn.F = tIn; } // 16
}";
var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70);
comp.VerifyEmitDiagnostics(
// (9,59): error CS8331: Cannot assign to field 'F' or use it as the right hand side of a ref assignment because it is a readonly variable
// static void AssignValueToValue<T>(S<T> s, T tValue) { s.F = tValue; } // 1
Diagnostic(ErrorCode.ERR_AssignReadonlyNotField, "s.F").WithArguments("field", "F").WithLocation(9, 59),
// (10,59): error CS8331: Cannot assign to field 'F' or use it as the right hand side of a ref assignment because it is a readonly variable
// static void AssignRefToValue<T>(S<T> s, ref T tRef) { s.F = tRef; } // 2
Diagnostic(ErrorCode.ERR_AssignReadonlyNotField, "s.F").WithArguments("field", "F").WithLocation(10, 59),
// (11,75): error CS8331: Cannot assign to field 'F' or use it as the right hand side of a ref assignment because it is a readonly variable
// static void AssignOutToValue<T>(S<T> s, out T tOut) { tOut = default; s.F = tOut; } // 3
Diagnostic(ErrorCode.ERR_AssignReadonlyNotField, "s.F").WithArguments("field", "F").WithLocation(11, 75),
// (12,59): error CS8331: Cannot assign to field 'F' or use it as the right hand side of a ref assignment because it is a readonly variable
// static void AssignInToValue<T>(S<T> s, in T tIn) { s.F = tIn; } // 4
Diagnostic(ErrorCode.ERR_AssignReadonlyNotField, "s.F").WithArguments("field", "F").WithLocation(12, 59),
// (14,64): error CS8331: Cannot assign to field 'F' or use it as the right hand side of a ref assignment because it is a readonly variable
// static void AssignValueToRef<T>(ref S<T> sRef, T tValue) { sRef.F = tValue; } // 5
Diagnostic(ErrorCode.ERR_AssignReadonlyNotField, "sRef.F").WithArguments("field", "F").WithLocation(14, 64),
// (15,64): error CS8331: Cannot assign to field 'F' or use it as the right hand side of a ref assignment because it is a readonly variable
// static void AssignRefToRef<T>(ref S<T> sRef, ref T tRef) { sRef.F = tRef; } // 6
Diagnostic(ErrorCode.ERR_AssignReadonlyNotField, "sRef.F").WithArguments("field", "F").WithLocation(15, 64),
// (16,80): error CS8331: Cannot assign to field 'F' or use it as the right hand side of a ref assignment because it is a readonly variable
// static void AssignOutToRef<T>(ref S<T> sRef, out T tOut) { tOut = default; sRef.F = tOut; } // 7
Diagnostic(ErrorCode.ERR_AssignReadonlyNotField, "sRef.F").WithArguments("field", "F").WithLocation(16, 80),
// (17,64): error CS8331: Cannot assign to field 'F' or use it as the right hand side of a ref assignment because it is a readonly variable
// static void AssignInToRef<T>(ref S<T> sRef, in T tIn) { sRef.F = tIn; } // 8
Diagnostic(ErrorCode.ERR_AssignReadonlyNotField, "sRef.F").WithArguments("field", "F").WithLocation(17, 64),
// (19,80): error CS8331: Cannot assign to field 'F' or use it as the right hand side of a ref assignment because it is a readonly variable
// static void AssignValueToOut<T>(out S<T> sOut, T tValue) { sOut = default; sOut.F = tValue; } // 9
Diagnostic(ErrorCode.ERR_AssignReadonlyNotField, "sOut.F").WithArguments("field", "F").WithLocation(19, 80),
// (20,80): error CS8331: Cannot assign to field 'F' or use it as the right hand side of a ref assignment because it is a readonly variable
// static void AssignRefToOut<T>(out S<T> sOut, ref T tRef) { sOut = default; sOut.F = tRef; } // 10
Diagnostic(ErrorCode.ERR_AssignReadonlyNotField, "sOut.F").WithArguments("field", "F").WithLocation(20, 80),
// (21,96): error CS8331: Cannot assign to field 'F' or use it as the right hand side of a ref assignment because it is a readonly variable
// static void AssignOutToOut<T>(out S<T> sOut, out T tOut) { sOut = default; tOut = default; sOut.F = tOut; } // 11
Diagnostic(ErrorCode.ERR_AssignReadonlyNotField, "sOut.F").WithArguments("field", "F").WithLocation(21, 96),
// (22,80): error CS8331: Cannot assign to field 'F' or use it as the right hand side of a ref assignment because it is a readonly variable
// static void AssignInToOut<T>(out S<T> sOut, in T tIn) { sOut = default; sOut.F = tIn; } // 12
Diagnostic(ErrorCode.ERR_AssignReadonlyNotField, "sOut.F").WithArguments("field", "F").WithLocation(22, 80),
// (24,61): error CS8331: Cannot assign to field 'F' or use it as the right hand side of a ref assignment because it is a readonly variable
// static void AssignValueToIn<T>(in S<T> sIn, T tValue) { sIn.F = tValue; } // 13
Diagnostic(ErrorCode.ERR_AssignReadonlyNotField, "sIn.F").WithArguments("field", "F").WithLocation(24, 61),
// (25,61): error CS8331: Cannot assign to field 'F' or use it as the right hand side of a ref assignment because it is a readonly variable
// static void AssignRefToIn<T>(in S<T> sIn, ref T tRef) { sIn.F = tRef; } // 14
Diagnostic(ErrorCode.ERR_AssignReadonlyNotField, "sIn.F").WithArguments("field", "F").WithLocation(25, 61),
// (26,77): error CS8331: Cannot assign to field 'F' or use it as the right hand side of a ref assignment because it is a readonly variable
// static void AssignOutToIn<T>(in S<T> sIn, out T tOut) { tOut = default; sIn.F = tOut; } // 15
Diagnostic(ErrorCode.ERR_AssignReadonlyNotField, "sIn.F").WithArguments("field", "F").WithLocation(26, 77),
// (27,61): error CS8331: Cannot assign to field 'F' or use it as the right hand side of a ref assignment because it is a readonly variable
// static void AssignInToIn<T>(in S<T> sIn, in T tIn) { sIn.F = tIn; } // 16
Diagnostic(ErrorCode.ERR_AssignReadonlyNotField, "sIn.F").WithArguments("field", "F").WithLocation(27, 61));
}
[Fact]
public void AssignValueTo_ReadonlyRefField()
{
var source =
@"using System;
ref struct S<T>
{
public readonly ref T F;
public S(ref T t) { F = ref t; }
}
class Program
{
static void AssignValueToValue<T>(S<T> s, T tValue) { s.F = tValue; }
static void AssignRefToValue<T>(S<T> s, ref T tRef) { s.F = tRef; }
static void AssignOutToValue<T>(S<T> s, out T tOut) { tOut = default; s.F = tOut; }
static void AssignInToValue<T>(S<T> s, in T tIn) { s.F = tIn; }
static void AssignValueToRef<T>(ref S<T> sRef, T tValue) { sRef.F = tValue; }
static void AssignRefToRef<T>(ref S<T> sRef, ref T tRef) { sRef.F = tRef; }
static void AssignOutToRef<T>(ref S<T> sRef, out T tOut) { tOut = default; sRef.F = tOut; }
static void AssignInToRef<T>(ref S<T> sRef, in T tIn) { sRef.F = tIn; }
static void AssignValueToOut<T>(out S<T> sOut, S<T> sInit, T tValue) { sOut = sInit; sOut.F = tValue; }
static void AssignRefToOut<T>(out S<T> sOut, S<T> sInit, ref T tRef) { sOut = sInit; sOut.F = tRef; }
static void AssignOutToOut<T>(out S<T> sOut, S<T> sInit, out T tOut) { sOut = sInit; tOut = default; sOut.F = tOut; }
static void AssignInToOut<T>(out S<T> sOut, S<T> sInit, in T tIn) { sOut = sInit; sOut.F = tIn; }
static void AssignValueToIn<T>(in S<T> sIn, T tValue) { sIn.F = tValue; }
static void AssignRefToIn<T>(in S<T> sIn, ref T tRef) { sIn.F = tRef; }
static void AssignOutToIn<T>(in S<T> sIn, out T tOut) { tOut = default; sIn.F = tOut; }
static void AssignInToIn<T>(in S<T> sIn, in T tIn) { sIn.F = tIn; }
static void Main()
{
int x, y;
scoped S<int> s;
x = 1; y = 2;
s = new S<int>(ref x);
AssignValueToValue(s, y);
Console.WriteLine(s.F);
x = 1; y = 2;
s = new S<int>(ref x);
AssignRefToValue(s, ref y);
Console.WriteLine(s.F);
x = 1; y = 2;
s = new S<int>(ref x);
AssignOutToValue(s, out y);
Console.WriteLine(s.F);
x = 1; y = 2;
s = new S<int>(ref x);
AssignInToValue(s, y);
Console.WriteLine(s.F);
x = 3; y = 4;
s = new S<int>(ref x);
AssignValueToRef(ref s, y);
Console.WriteLine(s.F);
x = 3; y = 4;
s = new S<int>(ref x);
AssignRefToRef(ref s, ref y);
Console.WriteLine(s.F);
x = 3; y = 4;
s = new S<int>(ref x);
AssignOutToRef(ref s, out y);
Console.WriteLine(s.F);
x = 3; y = 4;
s = new S<int>(ref x);
AssignInToRef(ref s, y);
Console.WriteLine(s.F);
x = 5; y = 6;
s = new S<int>(ref x);
AssignValueToOut(out s, new S<int>(ref x), y);
Console.WriteLine(s.F);
x = 5; y = 6;
s = new S<int>(ref x);
AssignRefToOut(out s, new S<int>(ref x), ref y);
Console.WriteLine(s.F);
x = 5; y = 6;
s = new S<int>(ref x);
AssignOutToOut(out s, new S<int>(ref x), out y);
Console.WriteLine(s.F);
x = 5; y = 6;
s = new S<int>(ref x);
AssignInToOut(out s, new S<int>(ref x), y);
Console.WriteLine(s.F);
x = 7; y = 8;
s = new S<int>(ref x);
AssignValueToIn(s, y);
Console.WriteLine(s.F);
x = 7; y = 8;
s = new S<int>(ref x);
AssignRefToIn(s, ref y);
Console.WriteLine(s.F);
x = 7; y = 8;
s = new S<int>(ref x);
AssignOutToIn(s, out y);
Console.WriteLine(s.F);
x = 7; y = 8;
s = new S<int>(ref x);
AssignInToIn(s, y);
Console.WriteLine(s.F);
}
}";
var comp = CreateCompilation(source, options: TestOptions.ReleaseExe, targetFramework: TargetFramework.Net70);
var verifier = CompileAndVerify(comp, verify: Verification.Skipped, expectedOutput: IncludeExpectedOutput(
@"2
2
0
2
4
4
0
4
6
6
0
6
8
8
0
8"));
verifier.VerifyILMultiple(
"Program.AssignValueToValue<T>",
@"{
// Code size 13 (0xd)
.maxstack 2
IL_0000: ldarg.0
IL_0001: ldfld ""ref T S<T>.F""
IL_0006: ldarg.1
IL_0007: stobj ""T""
IL_000c: ret
}",
"Program.AssignRefToValue<T>",
@"{
// Code size 18 (0x12)
.maxstack 2
IL_0000: ldarg.0
IL_0001: ldfld ""ref T S<T>.F""
IL_0006: ldarg.1
IL_0007: ldobj ""T""
IL_000c: stobj ""T""
IL_0011: ret
}",
"Program.AssignOutToValue<T>",
@"{
// Code size 25 (0x19)
.maxstack 2
IL_0000: ldarg.1
IL_0001: initobj ""T""
IL_0007: ldarg.0
IL_0008: ldfld ""ref T S<T>.F""
IL_000d: ldarg.1
IL_000e: ldobj ""T""
IL_0013: stobj ""T""
IL_0018: ret
}",
"Program.AssignInToValue<T>",
@"{
// Code size 18 (0x12)
.maxstack 2
IL_0000: ldarg.0
IL_0001: ldfld ""ref T S<T>.F""
IL_0006: ldarg.1
IL_0007: ldobj ""T""
IL_000c: stobj ""T""
IL_0011: ret
}",
"Program.AssignValueToRef<T>",
@"{
// Code size 13 (0xd)
.maxstack 2
IL_0000: ldarg.0
IL_0001: ldfld ""ref T S<T>.F""
IL_0006: ldarg.1
IL_0007: stobj ""T""
IL_000c: ret
}",
"Program.AssignRefToRef<T>",
@"{
// Code size 18 (0x12)
.maxstack 2
IL_0000: ldarg.0
IL_0001: ldfld ""ref T S<T>.F""
IL_0006: ldarg.1
IL_0007: ldobj ""T""
IL_000c: stobj ""T""
IL_0011: ret
}",
"Program.AssignOutToRef<T>",
@"{
// Code size 25 (0x19)
.maxstack 2
IL_0000: ldarg.1
IL_0001: initobj ""T""
IL_0007: ldarg.0
IL_0008: ldfld ""ref T S<T>.F""
IL_000d: ldarg.1
IL_000e: ldobj ""T""
IL_0013: stobj ""T""
IL_0018: ret
}",
"Program.AssignInToRef<T>",
@"{
// Code size 18 (0x12)
.maxstack 2
IL_0000: ldarg.0
IL_0001: ldfld ""ref T S<T>.F""
IL_0006: ldarg.1
IL_0007: ldobj ""T""
IL_000c: stobj ""T""
IL_0011: ret
}",
"Program.AssignValueToOut<T>",
@"{
// Code size 20 (0x14)
.maxstack 2
IL_0000: ldarg.0
IL_0001: ldarg.1
IL_0002: stobj ""S<T>""
IL_0007: ldarg.0
IL_0008: ldfld ""ref T S<T>.F""
IL_000d: ldarg.2
IL_000e: stobj ""T""
IL_0013: ret
}",
"Program.AssignRefToOut<T>",
@"{
// Code size 25 (0x19)
.maxstack 2
IL_0000: ldarg.0
IL_0001: ldarg.1
IL_0002: stobj ""S<T>""
IL_0007: ldarg.0
IL_0008: ldfld ""ref T S<T>.F""
IL_000d: ldarg.2
IL_000e: ldobj ""T""
IL_0013: stobj ""T""
IL_0018: ret
}",
"Program.AssignOutToOut<T>",
@"{
// Code size 32 (0x20)
.maxstack 2
IL_0000: ldarg.0
IL_0001: ldarg.1
IL_0002: stobj ""S<T>""
IL_0007: ldarg.2
IL_0008: initobj ""T""
IL_000e: ldarg.0
IL_000f: ldfld ""ref T S<T>.F""
IL_0014: ldarg.2
IL_0015: ldobj ""T""
IL_001a: stobj ""T""
IL_001f: ret
}",
"Program.AssignInToOut<T>",
@"{
// Code size 25 (0x19)
.maxstack 2
IL_0000: ldarg.0
IL_0001: ldarg.1
IL_0002: stobj ""S<T>""
IL_0007: ldarg.0
IL_0008: ldfld ""ref T S<T>.F""
IL_000d: ldarg.2
IL_000e: ldobj ""T""
IL_0013: stobj ""T""
IL_0018: ret
}",
"Program.AssignValueToIn<T>",
@"{
// Code size 13 (0xd)
.maxstack 2
IL_0000: ldarg.0
IL_0001: ldfld ""ref T S<T>.F""
IL_0006: ldarg.1
IL_0007: stobj ""T""
IL_000c: ret
}",
"Program.AssignRefToIn<T>",
@"{
// Code size 18 (0x12)
.maxstack 2
IL_0000: ldarg.0
IL_0001: ldfld ""ref T S<T>.F""
IL_0006: ldarg.1
IL_0007: ldobj ""T""
IL_000c: stobj ""T""
IL_0011: ret
}",
"Program.AssignOutToIn<T>",
@"{
// Code size 25 (0x19)
.maxstack 2
IL_0000: ldarg.1
IL_0001: initobj ""T""
IL_0007: ldarg.0
IL_0008: ldfld ""ref T S<T>.F""
IL_000d: ldarg.1
IL_000e: ldobj ""T""
IL_0013: stobj ""T""
IL_0018: ret
}",
"Program.AssignInToIn<T>",
@"{
// Code size 18 (0x12)
.maxstack 2
IL_0000: ldarg.0
IL_0001: ldfld ""ref T S<T>.F""
IL_0006: ldarg.1
IL_0007: ldobj ""T""
IL_000c: stobj ""T""
IL_0011: ret
}");
}
[Fact]
public void AssignValueTo_ReadonlyRefReadonlyField()
{
var source =
@"ref struct S<T>
{
public readonly ref readonly T F;
public S(ref T t) { F = ref t; }
}
class Program
{
static void AssignValueToValue<T>(S<T> s, T tValue) { s.F = tValue; } // 1
static void AssignRefToValue<T>(S<T> s, ref T tRef) { s.F = tRef; } // 2
static void AssignOutToValue<T>(S<T> s, out T tOut) { tOut = default; s.F = tOut; } // 3
static void AssignInToValue<T>(S<T> s, in T tIn) { s.F = tIn; } // 4
static void AssignValueToRef<T>(ref S<T> sRef, T tValue) { sRef.F = tValue; } // 5
static void AssignRefToRef<T>(ref S<T> sRef, ref T tRef) { sRef.F = tRef; } // 6
static void AssignOutToRef<T>(ref S<T> sRef, out T tOut) { tOut = default; sRef.F = tOut; } // 7
static void AssignInToRef<T>(ref S<T> sRef, in T tIn) { sRef.F = tIn; } // 8
static void AssignValueToOut<T>(out S<T> sOut, T tValue) { sOut = default; sOut.F = tValue; } // 9
static void AssignRefToOut<T>(out S<T> sOut, ref T tRef) { sOut = default; sOut.F = tRef; } // 10
static void AssignOutToOut<T>(out S<T> sOut, out T tOut) { sOut = default; tOut = default; sOut.F = tOut; } // 11
static void AssignInToOut<T>(out S<T> sOut, in T tIn) { sOut = default; sOut.F = tIn; } // 12
static void AssignValueToIn<T>(in S<T> sIn, T tValue) { sIn.F = tValue; } // 13
static void AssignRefToIn<T>(in S<T> sIn, ref T tRef) { sIn.F = tRef; } // 14
static void AssignOutToIn<T>(in S<T> sIn, out T tOut) { tOut = default; sIn.F = tOut; } // 15
static void AssignInToIn<T>(in S<T> sIn, in T tIn) { sIn.F = tIn; } // 16
}";
var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70);
comp.VerifyEmitDiagnostics(
// (9,59): error CS8331: Cannot assign to field 'F' or use it as the right hand side of a ref assignment because it is a readonly variable
// static void AssignValueToValue<T>(S<T> s, T tValue) { s.F = tValue; } // 1
Diagnostic(ErrorCode.ERR_AssignReadonlyNotField, "s.F").WithArguments("field", "F").WithLocation(9, 59),
// (10,59): error CS8331: Cannot assign to field 'F' or use it as the right hand side of a ref assignment because it is a readonly variable
// static void AssignRefToValue<T>(S<T> s, ref T tRef) { s.F = tRef; } // 2
Diagnostic(ErrorCode.ERR_AssignReadonlyNotField, "s.F").WithArguments("field", "F").WithLocation(10, 59),
// (11,75): error CS8331: Cannot assign to field 'F' or use it as the right hand side of a ref assignment because it is a readonly variable
// static void AssignOutToValue<T>(S<T> s, out T tOut) { tOut = default; s.F = tOut; } // 3
Diagnostic(ErrorCode.ERR_AssignReadonlyNotField, "s.F").WithArguments("field", "F").WithLocation(11, 75),
// (12,59): error CS8331: Cannot assign to field 'F' or use it as the right hand side of a ref assignment because it is a readonly variable
// static void AssignInToValue<T>(S<T> s, in T tIn) { s.F = tIn; } // 4
Diagnostic(ErrorCode.ERR_AssignReadonlyNotField, "s.F").WithArguments("field", "F").WithLocation(12, 59),
// (14,64): error CS8331: Cannot assign to field 'F' or use it as the right hand side of a ref assignment because it is a readonly variable
// static void AssignValueToRef<T>(ref S<T> sRef, T tValue) { sRef.F = tValue; } // 5
Diagnostic(ErrorCode.ERR_AssignReadonlyNotField, "sRef.F").WithArguments("field", "F").WithLocation(14, 64),
// (15,64): error CS8331: Cannot assign to field 'F' or use it as the right hand side of a ref assignment because it is a readonly variable
// static void AssignRefToRef<T>(ref S<T> sRef, ref T tRef) { sRef.F = tRef; } // 6
Diagnostic(ErrorCode.ERR_AssignReadonlyNotField, "sRef.F").WithArguments("field", "F").WithLocation(15, 64),
// (16,80): error CS8331: Cannot assign to field 'F' or use it as the right hand side of a ref assignment because it is a readonly variable
// static void AssignOutToRef<T>(ref S<T> sRef, out T tOut) { tOut = default; sRef.F = tOut; } // 7
Diagnostic(ErrorCode.ERR_AssignReadonlyNotField, "sRef.F").WithArguments("field", "F").WithLocation(16, 80),
// (17,64): error CS8331: Cannot assign to field 'F' or use it as the right hand side of a ref assignment because it is a readonly variable
// static void AssignInToRef<T>(ref S<T> sRef, in T tIn) { sRef.F = tIn; } // 8
Diagnostic(ErrorCode.ERR_AssignReadonlyNotField, "sRef.F").WithArguments("field", "F").WithLocation(17, 64),
// (19,80): error CS8331: Cannot assign to field 'F' or use it as the right hand side of a ref assignment because it is a readonly variable
// static void AssignValueToOut<T>(out S<T> sOut, T tValue) { sOut = default; sOut.F = tValue; } // 9
Diagnostic(ErrorCode.ERR_AssignReadonlyNotField, "sOut.F").WithArguments("field", "F").WithLocation(19, 80),
// (20,80): error CS8331: Cannot assign to field 'F' or use it as the right hand side of a ref assignment because it is a readonly variable
// static void AssignRefToOut<T>(out S<T> sOut, ref T tRef) { sOut = default; sOut.F = tRef; } // 10
Diagnostic(ErrorCode.ERR_AssignReadonlyNotField, "sOut.F").WithArguments("field", "F").WithLocation(20, 80),
// (21,96): error CS8331: Cannot assign to field 'F' or use it as the right hand side of a ref assignment because it is a readonly variable
// static void AssignOutToOut<T>(out S<T> sOut, out T tOut) { sOut = default; tOut = default; sOut.F = tOut; } // 11
Diagnostic(ErrorCode.ERR_AssignReadonlyNotField, "sOut.F").WithArguments("field", "F").WithLocation(21, 96),
// (22,80): error CS8331: Cannot assign to field 'F' or use it as the right hand side of a ref assignment because it is a readonly variable
// static void AssignInToOut<T>(out S<T> sOut, in T tIn) { sOut = default; sOut.F = tIn; } // 12
Diagnostic(ErrorCode.ERR_AssignReadonlyNotField, "sOut.F").WithArguments("field", "F").WithLocation(22, 80),
// (24,61): error CS8331: Cannot assign to field 'F' or use it as the right hand side of a ref assignment because it is a readonly variable
// static void AssignValueToIn<T>(in S<T> sIn, T tValue) { sIn.F = tValue; } // 13
Diagnostic(ErrorCode.ERR_AssignReadonlyNotField, "sIn.F").WithArguments("field", "F").WithLocation(24, 61),
// (25,61): error CS8331: Cannot assign to field 'F' or use it as the right hand side of a ref assignment because it is a readonly variable
// static void AssignRefToIn<T>(in S<T> sIn, ref T tRef) { sIn.F = tRef; } // 14
Diagnostic(ErrorCode.ERR_AssignReadonlyNotField, "sIn.F").WithArguments("field", "F").WithLocation(25, 61),
// (26,77): error CS8331: Cannot assign to field 'F' or use it as the right hand side of a ref assignment because it is a readonly variable
// static void AssignOutToIn<T>(in S<T> sIn, out T tOut) { tOut = default; sIn.F = tOut; } // 15
Diagnostic(ErrorCode.ERR_AssignReadonlyNotField, "sIn.F").WithArguments("field", "F").WithLocation(26, 77),
// (27,61): error CS8331: Cannot assign to field 'F' or use it as the right hand side of a ref assignment because it is a readonly variable
// static void AssignInToIn<T>(in S<T> sIn, in T tIn) { sIn.F = tIn; } // 16
Diagnostic(ErrorCode.ERR_AssignReadonlyNotField, "sIn.F").WithArguments("field", "F").WithLocation(27, 61));
}
[Fact]
public void AssignRefTo_RefField()
{
var source =
@"ref struct S<T>
{
public ref T F;
public S(ref T t) { F = ref t; }
}
class Program
{
static void AssignValueToValue<T>(S<T> s, T tValue) { s.F = ref tValue; } // 1
static void AssignRefToValue<T>(S<T> s, ref T tRef) { s.F = ref tRef; } // 2
static void AssignOutToValue<T>(S<T> s, out T tOut) { tOut = default; s.F = ref tOut; } // 3
static void AssignInToValue<T>(S<T> s, in T tIn) { s.F = ref tIn; } // 4
static void AssignValueToRef<T>(ref S<T> sRef, T tValue) { sRef.F = ref tValue; } // 5
static void AssignRefToRef<T>(ref S<T> sRef, ref T tRef) { sRef.F = ref tRef; } // 6
static void AssignOutToRef<T>(ref S<T> sRef, out T tOut) { tOut = default; sRef.F = ref tOut; } // 7
static void AssignInToRef<T>(ref S<T> sRef, in T tIn) { sRef.F = ref tIn; } // 8
static void AssignValueToOut<T>(out S<T> sOut, T tValue) { sOut = default; sOut.F = ref tValue; } // 9
static void AssignRefToOut<T>(out S<T> sOut, ref T tRef) { sOut = default; sOut.F = ref tRef; }
static void AssignOutToOut<T>(out S<T> sOut, out T tOut) { sOut = default; tOut = default; sOut.F = ref tOut; } // 10
static void AssignInToOut<T>(out S<T> sOut, in T tIn) { sOut = default; sOut.F = ref tIn; } // 11
static void AssignValueToIn<T>(in S<T> sIn, T tValue) { sIn.F = ref tValue; } // 12
static void AssignRefToIn<T>(in S<T> sIn, ref T tRef) { sIn.F = ref tRef; } // 13
static void AssignOutToIn<T>(in S<T> sIn, out T tOut) { tOut = default; sIn.F = ref tOut; } // 14
static void AssignInToIn<T>(in S<T> sIn, in T tIn) { sIn.F = ref tIn; } // 15
}";
var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70);
comp.VerifyEmitDiagnostics(
// (9,59): error CS8374: Cannot ref-assign 'tValue' to 'F' because 'tValue' has a narrower escape scope than 'F'.
// static void AssignValueToValue<T>(S<T> s, T tValue) { s.F = ref tValue; } // 1
Diagnostic(ErrorCode.ERR_RefAssignNarrower, "s.F = ref tValue").WithArguments("F", "tValue").WithLocation(9, 59),
// (10,59): error CS9079: Cannot ref-assign 'tRef' to 'F' because 'tRef' can only escape the current method through a return statement.
// static void AssignRefToValue<T>(S<T> s, ref T tRef) { s.F = ref tRef; } // 2
Diagnostic(ErrorCode.ERR_RefAssignReturnOnly, "s.F = ref tRef").WithArguments("F", "tRef").WithLocation(10, 59),
// (11,75): error CS8374: Cannot ref-assign 'tOut' to 'F' because 'tOut' has a narrower escape scope than 'F'.
// static void AssignOutToValue<T>(S<T> s, out T tOut) { tOut = default; s.F = ref tOut; } // 3
Diagnostic(ErrorCode.ERR_RefAssignNarrower, "s.F = ref tOut").WithArguments("F", "tOut").WithLocation(11, 75),
// (12,69): error CS8331: Cannot assign to variable 'tIn' or use it as the right hand side of a ref assignment because it is a readonly variable
// static void AssignInToValue<T>(S<T> s, in T tIn) { s.F = ref tIn; } // 4
Diagnostic(ErrorCode.ERR_AssignReadonlyNotField, "tIn").WithArguments("variable", "tIn").WithLocation(12, 69),
// (14,64): error CS8374: Cannot ref-assign 'tValue' to 'F' because 'tValue' has a narrower escape scope than 'F'.
// static void AssignValueToRef<T>(ref S<T> sRef, T tValue) { sRef.F = ref tValue; } // 5
Diagnostic(ErrorCode.ERR_RefAssignNarrower, "sRef.F = ref tValue").WithArguments("F", "tValue").WithLocation(14, 64),
// (15,64): error CS9079: Cannot ref-assign 'tRef' to 'F' because 'tRef' can only escape the current method through a return statement.
// static void AssignRefToRef<T>(ref S<T> sRef, ref T tRef) { sRef.F = ref tRef; } // 6
Diagnostic(ErrorCode.ERR_RefAssignReturnOnly, "sRef.F = ref tRef").WithArguments("F", "tRef").WithLocation(15, 64),
// (16,80): error CS8374: Cannot ref-assign 'tOut' to 'F' because 'tOut' has a narrower escape scope than 'F'.
// static void AssignOutToRef<T>(ref S<T> sRef, out T tOut) { tOut = default; sRef.F = ref tOut; } // 7
Diagnostic(ErrorCode.ERR_RefAssignNarrower, "sRef.F = ref tOut").WithArguments("F", "tOut").WithLocation(16, 80),
// (17,77): error CS8331: Cannot assign to variable 'tIn' or use it as the right hand side of a ref assignment because it is a readonly variable
// static void AssignInToRef<T>(ref S<T> sRef, in T tIn) { sRef.F = ref tIn; } // 8
Diagnostic(ErrorCode.ERR_AssignReadonlyNotField, "tIn").WithArguments("variable", "tIn").WithLocation(17, 77),
// (19,80): error CS8374: Cannot ref-assign 'tValue' to 'F' because 'tValue' has a narrower escape scope than 'F'.
// static void AssignValueToOut<T>(out S<T> sOut, T tValue) { sOut = default; sOut.F = ref tValue; } // 9
Diagnostic(ErrorCode.ERR_RefAssignNarrower, "sOut.F = ref tValue").WithArguments("F", "tValue").WithLocation(19, 80),
// (21,96): error CS8374: Cannot ref-assign 'tOut' to 'F' because 'tOut' has a narrower escape scope than 'F'.
// static void AssignOutToOut<T>(out S<T> sOut, out T tOut) { sOut = default; tOut = default; sOut.F = ref tOut; } // 10
Diagnostic(ErrorCode.ERR_RefAssignNarrower, "sOut.F = ref tOut").WithArguments("F", "tOut").WithLocation(21, 96),
// (22,93): error CS8331: Cannot assign to variable 'tIn' or use it as the right hand side of a ref assignment because it is a readonly variable
// static void AssignInToOut<T>(out S<T> sOut, in T tIn) { sOut = default; sOut.F = ref tIn; } // 11
Diagnostic(ErrorCode.ERR_AssignReadonlyNotField, "tIn").WithArguments("variable", "tIn").WithLocation(22, 93),
// (24,61): error CS8332: Cannot assign to a member of variable 'sIn' or use it as the right hand side of a ref assignment because it is a readonly variable
// static void AssignValueToIn<T>(in S<T> sIn, T tValue) { sIn.F = ref tValue; } // 12
Diagnostic(ErrorCode.ERR_AssignReadonlyNotField2, "sIn.F").WithArguments("variable", "sIn").WithLocation(24, 61),
// (25,61): error CS8332: Cannot assign to a member of variable 'sIn' or use it as the right hand side of a ref assignment because it is a readonly variable
// static void AssignRefToIn<T>(in S<T> sIn, ref T tRef) { sIn.F = ref tRef; } // 13
Diagnostic(ErrorCode.ERR_AssignReadonlyNotField2, "sIn.F").WithArguments("variable", "sIn").WithLocation(25, 61),
// (26,77): error CS8332: Cannot assign to a member of variable 'sIn' or use it as the right hand side of a ref assignment because it is a readonly variable
// static void AssignOutToIn<T>(in S<T> sIn, out T tOut) { tOut = default; sIn.F = ref tOut; } // 14
Diagnostic(ErrorCode.ERR_AssignReadonlyNotField2, "sIn.F").WithArguments("variable", "sIn").WithLocation(26, 77),
// (27,61): error CS8332: Cannot assign to a member of variable 'sIn' or use it as the right hand side of a ref assignment because it is a readonly variable
// static void AssignInToIn<T>(in S<T> sIn, in T tIn) { sIn.F = ref tIn; } // 15
Diagnostic(ErrorCode.ERR_AssignReadonlyNotField2, "sIn.F").WithArguments("variable", "sIn").WithLocation(27, 61));
// Valid cases from above.
source =
@"using System;
ref struct S<T>
{
public ref T F;
public S(ref T t) { F = ref t; }
}
class Program
{
static void AssignRefToOut<T>(out S<T> sOut, ref T tRef) { sOut = default; sOut.F = ref tRef; }
static void Main()
{
int x, y;
scoped S<int> s;
x = 5; y = 6;
s = new S<int>(ref x);
AssignRefToOut(out s, ref y);
Console.WriteLine(s.F);
}
}";
comp = CreateCompilation(source, options: TestOptions.ReleaseExe, targetFramework: TargetFramework.Net70);
var verifier = CompileAndVerify(comp, verify: Verification.Skipped, expectedOutput: IncludeExpectedOutput(
@"6"));
verifier.VerifyILMultiple(
"Program.AssignRefToOut<T>",
@"{
// Code size 15 (0xf)
.maxstack 2
IL_0000: ldarg.0
IL_0001: initobj ""S<T>""
IL_0007: ldarg.0
IL_0008: ldarg.1
IL_0009: stfld ""ref T S<T>.F""
IL_000e: ret
}");
}
[Fact]
public void AssignRefTo_RefReadonlyField()
{
var source =
@"ref struct S<T>
{
public ref readonly T F;
public S(ref T t) { F = ref t; }
}
class Program
{
static void AssignValueToValue<T>(S<T> s, T tValue) { s.F = ref tValue; } // 1
static void AssignRefToValue<T>(S<T> s, ref T tRef) { s.F = ref tRef; }
static void AssignOutToValue<T>(S<T> s, out T tOut) { tOut = default; s.F = ref tOut; } // 2
static void AssignInToValue<T>(S<T> s, in T tIn) { s.F = ref tIn; }
static void AssignValueToRef<T>(ref S<T> sRef, T tValue) { sRef.F = ref tValue; } // 3
static void AssignRefToRef<T>(ref S<T> sRef, ref T tRef) { sRef.F = ref tRef; }
static void AssignOutToRef<T>(ref S<T> sRef, out T tOut) { tOut = default; sRef.F = ref tOut; } // 4
static void AssignInToRef<T>(ref S<T> sRef, in T tIn) { sRef.F = ref tIn; }
static void AssignValueToOut<T>(out S<T> sOut, T tValue) { sOut = default; sOut.F = ref tValue; } // 5
static void AssignRefToOut<T>(out S<T> sOut, ref T tRef) { sOut = default; sOut.F = ref tRef; }
static void AssignOutToOut<T>(out S<T> sOut, out T tOut) { sOut = default; tOut = default; sOut.F = ref tOut; } // 6
static void AssignInToOut<T>(out S<T> sOut, in T tIn) { sOut = default; sOut.F = ref tIn; }
static void AssignValueToIn<T>(in S<T> sIn, T tValue) { sIn.F = ref tValue; } // 7
static void AssignRefToIn<T>(in S<T> sIn, ref T tRef) { sIn.F = ref tRef; } // 8
static void AssignOutToIn<T>(in S<T> sIn, out T tOut) { tOut = default; sIn.F = ref tOut; } // 9
static void AssignInToIn<T>(in S<T> sIn, in T tIn) { sIn.F = ref tIn; } // 10
}";
var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70);
comp.VerifyEmitDiagnostics(
// (9,59): error CS8374: Cannot ref-assign 'tValue' to 'F' because 'tValue' has a narrower escape scope than 'F'.
// static void AssignValueToValue<T>(S<T> s, T tValue) { s.F = ref tValue; } // 1
Diagnostic(ErrorCode.ERR_RefAssignNarrower, "s.F = ref tValue").WithArguments("F", "tValue").WithLocation(9, 59),
// (10,59): error CS9079: Cannot ref-assign 'tRef' to 'F' because 'tRef' can only escape the current method through a return statement.
// static void AssignRefToValue<T>(S<T> s, ref T tRef) { s.F = ref tRef; }
Diagnostic(ErrorCode.ERR_RefAssignReturnOnly, "s.F = ref tRef").WithArguments("F", "tRef").WithLocation(10, 59),
// (11,75): error CS8374: Cannot ref-assign 'tOut' to 'F' because 'tOut' has a narrower escape scope than 'F'.
// static void AssignOutToValue<T>(S<T> s, out T tOut) { tOut = default; s.F = ref tOut; } // 2
Diagnostic(ErrorCode.ERR_RefAssignNarrower, "s.F = ref tOut").WithArguments("F", "tOut").WithLocation(11, 75),
// (12,59): error CS9079: Cannot ref-assign 'tIn' to 'F' because 'tIn' can only escape the current method through a return statement.
// static void AssignInToValue<T>(S<T> s, in T tIn) { s.F = ref tIn; }
Diagnostic(ErrorCode.ERR_RefAssignReturnOnly, "s.F = ref tIn").WithArguments("F", "tIn").WithLocation(12, 59),
// (14,64): error CS8374: Cannot ref-assign 'tValue' to 'F' because 'tValue' has a narrower escape scope than 'F'.
// static void AssignValueToRef<T>(ref S<T> sRef, T tValue) { sRef.F = ref tValue; } // 3
Diagnostic(ErrorCode.ERR_RefAssignNarrower, "sRef.F = ref tValue").WithArguments("F", "tValue").WithLocation(14, 64),
// (15,64): error CS9079: Cannot ref-assign 'tRef' to 'F' because 'tRef' can only escape the current method through a return statement.
// static void AssignRefToRef<T>(ref S<T> sRef, ref T tRef) { sRef.F = ref tRef; }
Diagnostic(ErrorCode.ERR_RefAssignReturnOnly, "sRef.F = ref tRef").WithArguments("F", "tRef").WithLocation(15, 64),
// (16,80): error CS8374: Cannot ref-assign 'tOut' to 'F' because 'tOut' has a narrower escape scope than 'F'.
// static void AssignOutToRef<T>(ref S<T> sRef, out T tOut) { tOut = default; sRef.F = ref tOut; } // 4
Diagnostic(ErrorCode.ERR_RefAssignNarrower, "sRef.F = ref tOut").WithArguments("F", "tOut").WithLocation(16, 80),
// (17,64): error CS9079: Cannot ref-assign 'tIn' to 'F' because 'tIn' can only escape the current method through a return statement.
// static void AssignInToRef<T>(ref S<T> sRef, in T tIn) { sRef.F = ref tIn; }
Diagnostic(ErrorCode.ERR_RefAssignReturnOnly, "sRef.F = ref tIn").WithArguments("F", "tIn").WithLocation(17, 64),
// (19,80): error CS8374: Cannot ref-assign 'tValue' to 'F' because 'tValue' has a narrower escape scope than 'F'.
// static void AssignValueToOut<T>(out S<T> sOut, T tValue) { sOut = default; sOut.F = ref tValue; } // 5
Diagnostic(ErrorCode.ERR_RefAssignNarrower, "sOut.F = ref tValue").WithArguments("F", "tValue").WithLocation(19, 80),
// (21,96): error CS8374: Cannot ref-assign 'tOut' to 'F' because 'tOut' has a narrower escape scope than 'F'.
// static void AssignOutToOut<T>(out S<T> sOut, out T tOut) { sOut = default; tOut = default; sOut.F = ref tOut; } // 6
Diagnostic(ErrorCode.ERR_RefAssignNarrower, "sOut.F = ref tOut").WithArguments("F", "tOut").WithLocation(21, 96),
// (24,61): error CS8332: Cannot assign to a member of variable 'sIn' or use it as the right hand side of a ref assignment because it is a readonly variable
// static void AssignValueToIn<T>(in S<T> sIn, T tValue) { sIn.F = ref tValue; } // 7
Diagnostic(ErrorCode.ERR_AssignReadonlyNotField2, "sIn.F").WithArguments("variable", "sIn").WithLocation(24, 61),
// (25,61): error CS8332: Cannot assign to a member of variable 'sIn' or use it as the right hand side of a ref assignment because it is a readonly variable
// static void AssignRefToIn<T>(in S<T> sIn, ref T tRef) { sIn.F = ref tRef; } // 8
Diagnostic(ErrorCode.ERR_AssignReadonlyNotField2, "sIn.F").WithArguments("variable", "sIn").WithLocation(25, 61),
// (26,77): error CS8332: Cannot assign to a member of variable 'sIn' or use it as the right hand side of a ref assignment because it is a readonly variable
// static void AssignOutToIn<T>(in S<T> sIn, out T tOut) { tOut = default; sIn.F = ref tOut; } // 9
Diagnostic(ErrorCode.ERR_AssignReadonlyNotField2, "sIn.F").WithArguments("variable", "sIn").WithLocation(26, 77),
// (27,61): error CS8332: Cannot assign to a member of variable 'sIn' or use it as the right hand side of a ref assignment because it is a readonly variable
// static void AssignInToIn<T>(in S<T> sIn, in T tIn) { sIn.F = ref tIn; } // 10
Diagnostic(ErrorCode.ERR_AssignReadonlyNotField2, "sIn.F").WithArguments("variable", "sIn").WithLocation(27, 61));
// Valid cases from above.
source =
@"using System;
ref struct S<T>
{
public ref readonly T F;
public S(ref T t) { F = ref t; }
}
class Program
{
static void AssignRefToOut<T>(out S<T> sOut, ref T tRef) { sOut = default; sOut.F = ref tRef; }
static void AssignInToOut<T>(out S<T> sOut, in T tIn) { sOut = default; sOut.F = ref tIn; }
static void Main()
{
int x, y;
scoped S<int> s;
x = 5; y = 6;
s = new S<int>(ref x);
AssignRefToOut(out s, ref y);
Console.WriteLine(s.F);
x = 5; y = 6;
s = new S<int>(ref x);
AssignInToOut(out s, y);
Console.WriteLine(s.F);
}
}";
comp = CreateCompilation(source, options: TestOptions.ReleaseExe, targetFramework: TargetFramework.Net70);
var verifier = CompileAndVerify(comp, verify: Verification.Skipped, expectedOutput: IncludeExpectedOutput(
@"6
6"));
verifier.VerifyILMultiple(
"Program.AssignRefToOut<T>",
@"{
// Code size 15 (0xf)
.maxstack 2
IL_0000: ldarg.0
IL_0001: initobj ""S<T>""
IL_0007: ldarg.0
IL_0008: ldarg.1
IL_0009: stfld ""ref readonly T S<T>.F""
IL_000e: ret
}",
"Program.AssignInToOut<T>",
@"{
// Code size 15 (0xf)
.maxstack 2
IL_0000: ldarg.0
IL_0001: initobj ""S<T>""
IL_0007: ldarg.0
IL_0008: ldarg.1
IL_0009: stfld ""ref readonly T S<T>.F""
IL_000e: ret
}");
}
[Fact]
public void AssignRefTo_ReadonlyRefField()
{
var source =
@"ref struct S<T>
{
public readonly ref T F;
public S(ref T t) { F = ref t; }
}
class Program
{
static void AssignValueToValue<T>(S<T> s, T tValue) { s.F = ref tValue; } // 1
static void AssignRefToValue<T>(S<T> s, ref T tRef) { s.F = ref tRef; } // 2
static void AssignOutToValue<T>(S<T> s, out T tOut) { tOut = default; s.F = ref tOut; } // 3
static void AssignInToValue<T>(S<T> s, in T tIn) { s.F = ref tIn; } // 4
static void AssignValueToRef<T>(ref S<T> sRef, T tValue) { sRef.F = ref tValue; } // 5
static void AssignRefToRef<T>(ref S<T> sRef, ref T tRef) { sRef.F = ref tRef; } // 6
static void AssignOutToRef<T>(ref S<T> sRef, out T tOut) { tOut = default; sRef.F = ref tOut; } // 7
static void AssignInToRef<T>(ref S<T> sRef, in T tIn) { sRef.F = ref tIn; } // 8
static void AssignValueToOut<T>(out S<T> sOut, T tValue) { sOut = default; sOut.F = ref tValue; } // 9
static void AssignRefToOut<T>(out S<T> sOut, ref T tRef) { sOut = default; sOut.F = ref tRef; } // 10
static void AssignOutToOut<T>(out S<T> sOut, out T tOut) { sOut = default; tOut = default; sOut.F = ref tOut; } // 11
static void AssignInToOut<T>(out S<T> sOut, in T tIn) { sOut = default; sOut.F = ref tIn; } // 12
static void AssignValueToIn<T>(in S<T> sIn, T tValue) { sIn.F = ref tValue; } // 13
static void AssignRefToIn<T>(in S<T> sIn, ref T tRef) { sIn.F = ref tRef; } // 14
static void AssignOutToIn<T>(in S<T> sIn, out T tOut) { tOut = default; sIn.F = ref tOut; } // 15
static void AssignInToIn<T>(in S<T> sIn, in T tIn) { sIn.F = ref tIn; } // 16
}";
var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70);
comp.VerifyEmitDiagnostics(
// (9,59): 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)
// static void AssignValueToValue<T>(S<T> s, T tValue) { s.F = ref tValue; } // 1
Diagnostic(ErrorCode.ERR_AssgReadonly, "s.F").WithLocation(9, 59),
// (10,59): 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)
// static void AssignRefToValue<T>(S<T> s, ref T tRef) { s.F = ref tRef; } // 2
Diagnostic(ErrorCode.ERR_AssgReadonly, "s.F").WithLocation(10, 59),
// (11,75): 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)
// static void AssignOutToValue<T>(S<T> s, out T tOut) { tOut = default; s.F = ref tOut; } // 3
Diagnostic(ErrorCode.ERR_AssgReadonly, "s.F").WithLocation(11, 75),
// (12,59): 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)
// static void AssignInToValue<T>(S<T> s, in T tIn) { s.F = ref tIn; } // 4
Diagnostic(ErrorCode.ERR_AssgReadonly, "s.F").WithLocation(12, 59),
// (14,64): 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)
// static void AssignValueToRef<T>(ref S<T> sRef, T tValue) { sRef.F = ref tValue; } // 5
Diagnostic(ErrorCode.ERR_AssgReadonly, "sRef.F").WithLocation(14, 64),
// (15,64): 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)
// static void AssignRefToRef<T>(ref S<T> sRef, ref T tRef) { sRef.F = ref tRef; } // 6
Diagnostic(ErrorCode.ERR_AssgReadonly, "sRef.F").WithLocation(15, 64),
// (16,80): 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)
// static void AssignOutToRef<T>(ref S<T> sRef, out T tOut) { tOut = default; sRef.F = ref tOut; } // 7
Diagnostic(ErrorCode.ERR_AssgReadonly, "sRef.F").WithLocation(16, 80),
// (17,64): 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)
// static void AssignInToRef<T>(ref S<T> sRef, in T tIn) { sRef.F = ref tIn; } // 8
Diagnostic(ErrorCode.ERR_AssgReadonly, "sRef.F").WithLocation(17, 64),
// (19,80): 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)
// static void AssignValueToOut<T>(out S<T> sOut, T tValue) { sOut = default; sOut.F = ref tValue; } // 9
Diagnostic(ErrorCode.ERR_AssgReadonly, "sOut.F").WithLocation(19, 80),
// (20,80): 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)
// static void AssignRefToOut<T>(out S<T> sOut, ref T tRef) { sOut = default; sOut.F = ref tRef; } // 10
Diagnostic(ErrorCode.ERR_AssgReadonly, "sOut.F").WithLocation(20, 80),
// (21,96): 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)
// static void AssignOutToOut<T>(out S<T> sOut, out T tOut) { sOut = default; tOut = default; sOut.F = ref tOut; } // 11
Diagnostic(ErrorCode.ERR_AssgReadonly, "sOut.F").WithLocation(21, 96),
// (22,80): 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)
// static void AssignInToOut<T>(out S<T> sOut, in T tIn) { sOut = default; sOut.F = ref tIn; } // 12
Diagnostic(ErrorCode.ERR_AssgReadonly, "sOut.F").WithLocation(22, 80),
// (24,61): 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)
// static void AssignValueToIn<T>(in S<T> sIn, T tValue) { sIn.F = ref tValue; } // 13
Diagnostic(ErrorCode.ERR_AssgReadonly, "sIn.F").WithLocation(24, 61),
// (25,61): 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)
// static void AssignRefToIn<T>(in S<T> sIn, ref T tRef) { sIn.F = ref tRef; } // 14
Diagnostic(ErrorCode.ERR_AssgReadonly, "sIn.F").WithLocation(25, 61),
// (26,77): 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)
// static void AssignOutToIn<T>(in S<T> sIn, out T tOut) { tOut = default; sIn.F = ref tOut; } // 15
Diagnostic(ErrorCode.ERR_AssgReadonly, "sIn.F").WithLocation(26, 77),
// (27,61): 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)
// static void AssignInToIn<T>(in S<T> sIn, in T tIn) { sIn.F = ref tIn; } // 16
Diagnostic(ErrorCode.ERR_AssgReadonly, "sIn.F").WithLocation(27, 61));
}
[Fact]
public void AssignRefTo_ReadonlyRefReadonlyField()
{
var source =
@"ref struct S<T>
{
public readonly ref readonly T F;
public S(ref T t) { F = ref t; }
}
class Program
{
static void AssignValueToValue<T>(S<T> s, T tValue) { s.F = ref tValue; } // 1
static void AssignRefToValue<T>(S<T> s, ref T tRef) { s.F = ref tRef; } // 2
static void AssignOutToValue<T>(S<T> s, out T tOut) { tOut = default; s.F = ref tOut; } // 3
static void AssignInToValue<T>(S<T> s, in T tIn) { s.F = ref tIn; } // 4
static void AssignValueToRef<T>(ref S<T> sRef, T tValue) { sRef.F = ref tValue; } // 5
static void AssignRefToRef<T>(ref S<T> sRef, ref T tRef) { sRef.F = ref tRef; } // 6
static void AssignOutToRef<T>(ref S<T> sRef, out T tOut) { tOut = default; sRef.F = ref tOut; } // 7
static void AssignInToRef<T>(ref S<T> sRef, in T tIn) { sRef.F = ref tIn; } // 8
static void AssignValueToOut<T>(out S<T> sOut, T tValue) { sOut = default; sOut.F = ref tValue; } // 9
static void AssignRefToOut<T>(out S<T> sOut, ref T tRef) { sOut = default; sOut.F = ref tRef; } // 10
static void AssignOutToOut<T>(out S<T> sOut, out T tOut) { sOut = default; tOut = default; sOut.F = ref tOut; } // 11
static void AssignInToOut<T>(out S<T> sOut, in T tIn) { sOut = default; sOut.F = ref tIn; } // 12
static void AssignValueToIn<T>(in S<T> sIn, T tValue) { sIn.F = ref tValue; } // 13
static void AssignRefToIn<T>(in S<T> sIn, ref T tRef) { sIn.F = ref tRef; } // 14
static void AssignOutToIn<T>(in S<T> sIn, out T tOut) { tOut = default; sIn.F = ref tOut; } // 15
static void AssignInToIn<T>(in S<T> sIn, in T tIn) { sIn.F = ref tIn; } // 16
}";
var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70);
comp.VerifyEmitDiagnostics(
// (9,59): 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)
// static void AssignValueToValue<T>(S<T> s, T tValue) { s.F = ref tValue; } // 1
Diagnostic(ErrorCode.ERR_AssgReadonly, "s.F").WithLocation(9, 59),
// (10,59): 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)
// static void AssignRefToValue<T>(S<T> s, ref T tRef) { s.F = ref tRef; } // 2
Diagnostic(ErrorCode.ERR_AssgReadonly, "s.F").WithLocation(10, 59),
// (11,75): 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)
// static void AssignOutToValue<T>(S<T> s, out T tOut) { tOut = default; s.F = ref tOut; } // 3
Diagnostic(ErrorCode.ERR_AssgReadonly, "s.F").WithLocation(11, 75),
// (12,59): 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)
// static void AssignInToValue<T>(S<T> s, in T tIn) { s.F = ref tIn; } // 4
Diagnostic(ErrorCode.ERR_AssgReadonly, "s.F").WithLocation(12, 59),
// (14,64): 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)
// static void AssignValueToRef<T>(ref S<T> sRef, T tValue) { sRef.F = ref tValue; } // 5
Diagnostic(ErrorCode.ERR_AssgReadonly, "sRef.F").WithLocation(14, 64),
// (15,64): 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)
// static void AssignRefToRef<T>(ref S<T> sRef, ref T tRef) { sRef.F = ref tRef; } // 6
Diagnostic(ErrorCode.ERR_AssgReadonly, "sRef.F").WithLocation(15, 64),
// (16,80): 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)
// static void AssignOutToRef<T>(ref S<T> sRef, out T tOut) { tOut = default; sRef.F = ref tOut; } // 7
Diagnostic(ErrorCode.ERR_AssgReadonly, "sRef.F").WithLocation(16, 80),
// (17,64): 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)
// static void AssignInToRef<T>(ref S<T> sRef, in T tIn) { sRef.F = ref tIn; } // 8
Diagnostic(ErrorCode.ERR_AssgReadonly, "sRef.F").WithLocation(17, 64),
// (19,80): 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)
// static void AssignValueToOut<T>(out S<T> sOut, T tValue) { sOut = default; sOut.F = ref tValue; } // 9
Diagnostic(ErrorCode.ERR_AssgReadonly, "sOut.F").WithLocation(19, 80),
// (20,80): 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)
// static void AssignRefToOut<T>(out S<T> sOut, ref T tRef) { sOut = default; sOut.F = ref tRef; } // 10
Diagnostic(ErrorCode.ERR_AssgReadonly, "sOut.F").WithLocation(20, 80),
// (21,96): 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)
// static void AssignOutToOut<T>(out S<T> sOut, out T tOut) { sOut = default; tOut = default; sOut.F = ref tOut; } // 11
Diagnostic(ErrorCode.ERR_AssgReadonly, "sOut.F").WithLocation(21, 96),
// (22,80): 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)
// static void AssignInToOut<T>(out S<T> sOut, in T tIn) { sOut = default; sOut.F = ref tIn; } // 12
Diagnostic(ErrorCode.ERR_AssgReadonly, "sOut.F").WithLocation(22, 80),
// (24,61): 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)
// static void AssignValueToIn<T>(in S<T> sIn, T tValue) { sIn.F = ref tValue; } // 13
Diagnostic(ErrorCode.ERR_AssgReadonly, "sIn.F").WithLocation(24, 61),
// (25,61): 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)
// static void AssignRefToIn<T>(in S<T> sIn, ref T tRef) { sIn.F = ref tRef; } // 14
Diagnostic(ErrorCode.ERR_AssgReadonly, "sIn.F").WithLocation(25, 61),
// (26,77): 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)
// static void AssignOutToIn<T>(in S<T> sIn, out T tOut) { tOut = default; sIn.F = ref tOut; } // 15
Diagnostic(ErrorCode.ERR_AssgReadonly, "sIn.F").WithLocation(26, 77),
// (27,61): 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)
// static void AssignInToIn<T>(in S<T> sIn, in T tIn) { sIn.F = ref tIn; } // 16
Diagnostic(ErrorCode.ERR_AssgReadonly, "sIn.F").WithLocation(27, 61));
}
[Fact]
public void AssignOutParameterFrom_RefField()
{
var source =
@"#pragma warning disable 649
ref struct S<T>
{
public ref T Ref;
public ref readonly T RefReadonly;
public readonly ref T ReadonlyRef;
public readonly ref readonly T ReadonlyRefReadonly;
}
class Program
{
static void FromValueRef<T>(S<T> s, out T t) { t = s.Ref; }
static void FromValueRefReadonly<T>(S<T> s, out T t) { t = s.RefReadonly; }
static void FromValueReadonlyRef<T>(S<T> s, out T t) { t = s.ReadonlyRef; }
static void FromValueReadonlyRefReadonly<T>(S<T> s, out T t) { t = s.ReadonlyRefReadonly; }
static void FromRefRef<T>(ref S<T> s, out T t) { t = s.Ref; }
static void FromRefRefReadonly<T>(ref S<T> s, out T t) { t = s.RefReadonly; }
static void FromRefReadonlyRef<T>(ref S<T> s, out T t) { t = s.ReadonlyRef; }
static void FromRefReadonlyRefReadonly<T>(ref S<T> s, out T t) { t = s.ReadonlyRefReadonly; }
static void FromOutRef<T>(out S<T> s, out T t) { s = default; t = s.Ref; }
static void FromOutRefReadonly<T>(out S<T> s, out T t) { s = default; t = s.RefReadonly; }
static void FromOutReadonlyRef<T>(out S<T> s, out T t) { s = default; t = s.ReadonlyRef; }
static void FromOutReadonlyRefReadonly<T>(out S<T> s, out T t) { s = default; t = s.ReadonlyRefReadonly; }
static void FromInRef<T>(in S<T> s, out T t) { t = s.Ref; }
static void FromInRefReadonly<T>(in S<T> s, out T t) { t = s.RefReadonly; }
static void FromInReadonlyRef<T>(in S<T> s, out T t) { t = s.ReadonlyRef; }
static void FromInReadonlyRefReadonly<T>(in S<T> s, out T t) { t = s.ReadonlyRefReadonly; }
}";
var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70);
comp.VerifyEmitDiagnostics();
}
[Fact]
public void AssignRefLocalFrom_RefField()
{
var source =
@"ref struct S<T>
{
public ref T Ref;
public ref readonly T RefReadonly;
public readonly ref T ReadonlyRef;
public readonly ref readonly T ReadonlyRefReadonly;
}
class Program
{
static void FromValueRef<T>(S<T> s) { ref T t = ref s.Ref; }
static void FromValueRefReadonly<T>(S<T> s) { ref T t = ref s.RefReadonly; } // 1
static void FromValueReadonlyRef<T>(S<T> s) { ref T t = ref s.ReadonlyRef; }
static void FromValueReadonlyRefReadonly<T>(S<T> s) { ref T t = ref s.ReadonlyRefReadonly; } // 2
static void FromRefRef<T>(ref S<T> s) { ref T t = ref s.Ref; }
static void FromRefRefReadonly<T>(ref S<T> s) { ref T t = ref s.RefReadonly; } // 3
static void FromRefReadonlyRef<T>(ref S<T> s) { ref T t = ref s.ReadonlyRef; }
static void FromRefReadonlyRefReadonly<T>(ref S<T> s) { ref T t = ref s.ReadonlyRefReadonly; } // 4
static void FromOutRef<T>(out S<T> s) { s = default; ref T t = ref s.Ref; }
static void FromOutRefReadonly<T>(out S<T> s) { s = default; ref T t = ref s.RefReadonly; } // 5
static void FromOutReadonlyRef<T>(out S<T> s) { s = default; ref T t = ref s.ReadonlyRef; }
static void FromOutReadonlyRefReadonly<T>(out S<T> s) { s = default; ref T t = ref s.ReadonlyRefReadonly; } // 6
static void FromInRef<T>(in S<T> s) { ref T t = ref s.Ref; }
static void FromInRefReadonly<T>(in S<T> s) { ref T t = ref s.RefReadonly; } // 7
static void FromInReadonlyRef<T>(in S<T> s) { ref T t = ref s.ReadonlyRef; }
static void FromInReadonlyRefReadonly<T>(in S<T> s) { ref T t = ref s.ReadonlyRefReadonly; } // 8
}";
var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70);
comp.VerifyEmitDiagnostics(
// (12,73): error CS8329: Cannot use field 'RefReadonly' as a ref or out value because it is a readonly variable
// static void FromValueRefReadonly<T>(S<T> s) { ref T t = ref s.RefReadonly; } // 1
Diagnostic(ErrorCode.ERR_RefReadonlyNotField, "s.RefReadonly").WithArguments("field", "RefReadonly").WithLocation(12, 73),
// (14,73): error CS8329: Cannot use field 'ReadonlyRefReadonly' as a ref or out value because it is a readonly variable
// static void FromValueReadonlyRefReadonly<T>(S<T> s) { ref T t = ref s.ReadonlyRefReadonly; } // 2
Diagnostic(ErrorCode.ERR_RefReadonlyNotField, "s.ReadonlyRefReadonly").WithArguments("field", "ReadonlyRefReadonly").WithLocation(14, 73),
// (17,75): error CS8329: Cannot use field 'RefReadonly' as a ref or out value because it is a readonly variable
// static void FromRefRefReadonly<T>(ref S<T> s) { ref T t = ref s.RefReadonly; } // 3
Diagnostic(ErrorCode.ERR_RefReadonlyNotField, "s.RefReadonly").WithArguments("field", "RefReadonly").WithLocation(17, 75),
// (19,75): error CS8329: Cannot use field 'ReadonlyRefReadonly' as a ref or out value because it is a readonly variable
// static void FromRefReadonlyRefReadonly<T>(ref S<T> s) { ref T t = ref s.ReadonlyRefReadonly; } // 4
Diagnostic(ErrorCode.ERR_RefReadonlyNotField, "s.ReadonlyRefReadonly").WithArguments("field", "ReadonlyRefReadonly").WithLocation(19, 75),
// (22,88): error CS8329: Cannot use field 'RefReadonly' as a ref or out value because it is a readonly variable
// static void FromOutRefReadonly<T>(out S<T> s) { s = default; ref T t = ref s.RefReadonly; } // 5
Diagnostic(ErrorCode.ERR_RefReadonlyNotField, "s.RefReadonly").WithArguments("field", "RefReadonly").WithLocation(22, 88),
// (24,88): error CS8329: Cannot use field 'ReadonlyRefReadonly' as a ref or out value because it is a readonly variable
// static void FromOutReadonlyRefReadonly<T>(out S<T> s) { s = default; ref T t = ref s.ReadonlyRefReadonly; } // 6
Diagnostic(ErrorCode.ERR_RefReadonlyNotField, "s.ReadonlyRefReadonly").WithArguments("field", "ReadonlyRefReadonly").WithLocation(24, 88),
// (27,73): error CS8329: Cannot use field 'RefReadonly' as a ref or out value because it is a readonly variable
// static void FromInRefReadonly<T>(in S<T> s) { ref T t = ref s.RefReadonly; } // 7
Diagnostic(ErrorCode.ERR_RefReadonlyNotField, "s.RefReadonly").WithArguments("field", "RefReadonly").WithLocation(27, 73),
// (29,73): error CS8329: Cannot use field 'ReadonlyRefReadonly' as a ref or out value because it is a readonly variable
// static void FromInReadonlyRefReadonly<T>(in S<T> s) { ref T t = ref s.ReadonlyRefReadonly; } // 8
Diagnostic(ErrorCode.ERR_RefReadonlyNotField, "s.ReadonlyRefReadonly").WithArguments("field", "ReadonlyRefReadonly").WithLocation(29, 73));
}
[Fact]
public void AssignRefReadonlyLocalFrom_RefField()
{
var source =
@"ref struct S<T>
{
public ref T Ref;
public ref readonly T RefReadonly;
public readonly ref T ReadonlyRef;
public readonly ref readonly T ReadonlyRefReadonly;
}
class Program
{
static void FromValueRef<T>(S<T> s) { ref readonly T t = ref s.Ref; }
static void FromValueRefReadonly<T>(S<T> s) { ref readonly T t = ref s.RefReadonly; }
static void FromValueReadonlyRef<T>(S<T> s) { ref readonly T t = ref s.ReadonlyRef; }
static void FromValueReadonlyRefReadonly<T>(S<T> s) { ref readonly T t = ref s.ReadonlyRefReadonly; }
static void FromRefRef<T>(ref S<T> s) { ref readonly T t = ref s.Ref; }
static void FromRefRefReadonly<T>(ref S<T> s) { ref readonly T t = ref s.RefReadonly; }
static void FromRefReadonlyRef<T>(ref S<T> s) { ref readonly T t = ref s.ReadonlyRef; }
static void FromRefReadonlyRefReadonly<T>(ref S<T> s) { ref readonly T t = ref s.ReadonlyRefReadonly; }
static void FromOutRef<T>(out S<T> s) { s = default; ref readonly T t = ref s.Ref; }
static void FromOutRefReadonly<T>(out S<T> s) { s = default; ref readonly T t = ref s.RefReadonly; }
static void FromOutReadonlyRef<T>(out S<T> s) { s = default; ref readonly T t = ref s.ReadonlyRef; }
static void FromOutReadonlyRefReadonly<T>(out S<T> s) { s = default; ref readonly T t = ref s.ReadonlyRefReadonly; }
static void FromInRef<T>(in S<T> s) { ref readonly T t = ref s.Ref; }
static void FromInRefReadonly<T>(in S<T> s) { ref readonly T t = ref s.RefReadonly; }
static void FromInReadonlyRef<T>(in S<T> s) { ref readonly T t = ref s.ReadonlyRef; }
static void FromInReadonlyRefReadonly<T>(in S<T> s) { ref readonly T t = ref s.ReadonlyRefReadonly; }
}";
var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70);
comp.VerifyEmitDiagnostics();
}
[Fact]
public void RefReturn()
{
var source =
@"class Program
{
static ref T F1<T>(T t) => ref t; // 1
static ref T F2<T>(ref T t) => ref t;
static ref T F3<T>(out T t) { t = default; return ref t; } // 2
static ref T F4<T>(in T t) => ref t; // 3
static ref readonly T F5<T>(T t) => ref t; // 4
static ref readonly T F6<T>(ref T t) => ref t;
static ref readonly T F7<T>(out T t) { t = default; return ref t; } // 5
static ref readonly T F8<T>(in T t) => ref t;
}";
var comp = CreateCompilation(source);
comp.VerifyEmitDiagnostics(
// (3,36): error CS8166: Cannot return a parameter by reference 't' because it is not a ref parameter
// static ref T F1<T>(T t) => ref t; // 1
Diagnostic(ErrorCode.ERR_RefReturnParameter, "t").WithArguments("t").WithLocation(3, 36),
// (5,59): error CS9075: Cannot return a parameter by reference 't' because it is scoped to the current method
// static ref T F3<T>(out T t) { t = default; return ref t; } // 2
Diagnostic(ErrorCode.ERR_RefReturnScopedParameter, "t").WithArguments("t").WithLocation(5, 59),
// (6,39): error CS8333: Cannot return variable 't' by writable reference because it is a readonly variable
// static ref T F4<T>(in T t) => ref t; // 3
Diagnostic(ErrorCode.ERR_RefReturnReadonlyNotField, "t").WithArguments("variable", "t").WithLocation(6, 39),
// (7,45): error CS8166: Cannot return a parameter by reference 't' because it is not a ref parameter
// static ref readonly T F5<T>(T t) => ref t; // 4
Diagnostic(ErrorCode.ERR_RefReturnParameter, "t").WithArguments("t").WithLocation(7, 45),
// (9,68): error CS9075: Cannot return a parameter by reference 't' because it is scoped to the current method
// static ref readonly T F7<T>(out T t) { t = default; return ref t; } // 5
Diagnostic(ErrorCode.ERR_RefReturnScopedParameter, "t").WithArguments("t").WithLocation(9, 68));
}
[Fact]
public void RefReturn_Ref()
{
var source =
@"ref struct S<T>
{
public ref T F;
public ref T F1() => ref F;
public ref readonly T F2() => ref F;
}
class Program
{
static ref T F3<T>(S<T> s) => ref s.F;
static ref T F4<T>(ref S<T> s) => ref s.F;
static ref T F5<T>(out S<T> s) { s = default; return ref s.F; }
static ref T F6<T>(in S<T> s) => ref s.F;
static ref readonly T F7<T>(S<T> s) => ref s.F;
static ref readonly T F8<T>(ref S<T> s) => ref s.F;
static ref readonly T F9<T>(out S<T> s) { s = default; return ref s.F; }
static ref readonly T F10<T>(in S<T> s) => ref s.F;
}";
var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70);
comp.VerifyEmitDiagnostics();
}
[Fact]
public void RefReturn_RefReadonly()
{
var source =
@"ref struct S<T>
{
public ref readonly T F;
public ref T F1() => ref F;
public ref readonly T F2() => ref F;
}
class Program
{
static ref T F3<T>(S<T> s) => ref s.F;
static ref T F4<T>(ref S<T> s) => ref s.F;
static ref T F5<T>(out S<T> s) { s = default; return ref s.F; }
static ref T F6<T>(in S<T> s) => ref s.F;
static ref readonly T F7<T>(S<T> s) => ref s.F;
static ref readonly T F8<T>(ref S<T> s) => ref s.F;
static ref readonly T F9<T>(out S<T> s) { s = default; return ref s.F; }
static ref readonly T F10<T>(in S<T> s) => ref s.F;
}";
var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70);
comp.VerifyEmitDiagnostics(
// (4,30): error CS8333: Cannot return field 'F' by writable reference because it is a readonly variable
// public ref T F1() => ref F;
Diagnostic(ErrorCode.ERR_RefReturnReadonlyNotField, "F").WithArguments("field", "F").WithLocation(4, 30),
// (9,39): error CS8333: Cannot return field 'F' by writable reference because it is a readonly variable
// static ref T F3<T>(S<T> s) => ref s.F;
Diagnostic(ErrorCode.ERR_RefReturnReadonlyNotField, "s.F").WithArguments("field", "F").WithLocation(9, 39),
// (10,43): error CS8333: Cannot return field 'F' by writable reference because it is a readonly variable
// static ref T F4<T>(ref S<T> s) => ref s.F;
Diagnostic(ErrorCode.ERR_RefReturnReadonlyNotField, "s.F").WithArguments("field", "F").WithLocation(10, 43),
// (11,62): error CS8333: Cannot return field 'F' by writable reference because it is a readonly variable
// static ref T F5<T>(out S<T> s) { s = default; return ref s.F; }
Diagnostic(ErrorCode.ERR_RefReturnReadonlyNotField, "s.F").WithArguments("field", "F").WithLocation(11, 62),
// (12,42): error CS8333: Cannot return field 'F' by writable reference because it is a readonly variable
// static ref T F6<T>(in S<T> s) => ref s.F;
Diagnostic(ErrorCode.ERR_RefReturnReadonlyNotField, "s.F").WithArguments("field", "F").WithLocation(12, 42));
}
[Fact]
public void RefReturn_ReadonlyRef()
{
var source =
@"ref struct S<T>
{
public readonly ref T F;
public ref T F1() => ref F;
public ref readonly T F2() => ref F;
}
class Program
{
static ref T F3<T>(S<T> s) => ref s.F;
static ref T F4<T>(ref S<T> s) => ref s.F;
static ref T F5<T>(out S<T> s) { s = default; return ref s.F; }
static ref T F6<T>(in S<T> s) => ref s.F;
static ref readonly T F7<T>(S<T> s) => ref s.F;
static ref readonly T F8<T>(ref S<T> s) => ref s.F;
static ref readonly T F9<T>(out S<T> s) { s = default; return ref s.F; }
static ref readonly T F10<T>(in S<T> s) => ref s.F;
}";
var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70);
comp.VerifyEmitDiagnostics();
}
[Fact]
public void RefReturn_ReadonlyRefReadonly()
{
var source =
@"ref struct S<T>
{
public readonly ref readonly T F;
public ref T F1() => ref F;
public ref readonly T F2() => ref F;
}
class Program
{
static ref T F3<T>(S<T> s) => ref s.F;
static ref T F4<T>(ref S<T> s) => ref s.F;
static ref T F5<T>(out S<T> s) { s = default; return ref s.F; }
static ref T F6<T>(in S<T> s) => ref s.F;
static ref readonly T F7<T>(S<T> s) => ref s.F;
static ref readonly T F8<T>(ref S<T> s) => ref s.F;
static ref readonly T F9<T>(out S<T> s) { s = default; return ref s.F; }
static ref readonly T F10<T>(in S<T> s) => ref s.F;
}";
var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70);
comp.VerifyEmitDiagnostics(
// (4,30): error CS8333: Cannot return field 'F' by writable reference because it is a readonly variable
// public ref T F1() => ref F;
Diagnostic(ErrorCode.ERR_RefReturnReadonlyNotField, "F").WithArguments("field", "F").WithLocation(4, 30),
// (9,39): error CS8333: Cannot return field 'F' by writable reference because it is a readonly variable
// static ref T F3<T>(S<T> s) => ref s.F;
Diagnostic(ErrorCode.ERR_RefReturnReadonlyNotField, "s.F").WithArguments("field", "F").WithLocation(9, 39),
// (10,43): error CS8333: Cannot return field 'F' by writable reference because it is a readonly variable
// static ref T F4<T>(ref S<T> s) => ref s.F;
Diagnostic(ErrorCode.ERR_RefReturnReadonlyNotField, "s.F").WithArguments("field", "F").WithLocation(10, 43),
// (11,62): error CS8333: Cannot return field 'F' by writable reference because it is a readonly variable
// static ref T F5<T>(out S<T> s) { s = default; return ref s.F; }
Diagnostic(ErrorCode.ERR_RefReturnReadonlyNotField, "s.F").WithArguments("field", "F").WithLocation(11, 62),
// (12,42): error CS8333: Cannot return field 'F' by writable reference because it is a readonly variable
// static ref T F6<T>(in S<T> s) => ref s.F;
Diagnostic(ErrorCode.ERR_RefReturnReadonlyNotField, "s.F").WithArguments("field", "F").WithLocation(12, 42));
}
[Fact]
public void RefParameter_InstanceMethod_Ref()
{
var source =
@"ref struct S<T>
{
public ref T F;
public S(ref T t)
{
F = ref t;
M1(F);
M2(ref F);
M3(out F);
M4(F);
M4(in F);
}
object P
{
init
{
M1(F);
M2(ref F);
M3(out F);
M4(F);
M4(in F);
}
}
void M()
{
M1(F);
M2(ref F);
M3(out F);
M4(F);
M4(in F);
}
static void M1(T t) { }
static void M2(ref T t) { }
static void M3(out T t) { t = default; }
static void M4(in T t) { }
}";
var comp = CreateCompilation(new[] { source, IsExternalInitTypeDefinition }, targetFramework: TargetFramework.Net70);
comp.VerifyEmitDiagnostics();
}
[Fact]
public void RefParameter_InstanceMethod_RefReadonly()
{
var source =
@"ref struct S<T>
{
public ref readonly T F;
public S(ref T t)
{
F = ref t;
M1(F);
M2(ref F); // 1
M3(out F); // 2
M4(F);
M4(in F);
}
object P
{
init
{
M1(F);
M2(ref F); // 3
M3(out F); // 4
M4(F);
M4(in F);
}
}
void M()
{
M1(F);
M2(ref F); // 5
M3(out F); // 6
M4(F);
M4(in F);
}
static void M1(T t) { }
static void M2(ref T t) { }
static void M3(out T t) { t = default; }
static void M4(in T t) { }
}";
var comp = CreateCompilation(new[] { source, IsExternalInitTypeDefinition }, targetFramework: TargetFramework.Net70);
comp.VerifyEmitDiagnostics(
// (8,16): error CS8329: Cannot use field 'F' as a ref or out value because it is a readonly variable
// M2(ref F); // 1
Diagnostic(ErrorCode.ERR_RefReadonlyNotField, "F").WithArguments("field", "F").WithLocation(8, 16),
// (9,16): error CS8329: Cannot use field 'F' as a ref or out value because it is a readonly variable
// M3(out F); // 2
Diagnostic(ErrorCode.ERR_RefReadonlyNotField, "F").WithArguments("field", "F").WithLocation(9, 16),
// (18,20): error CS8329: Cannot use field 'F' as a ref or out value because it is a readonly variable
// M2(ref F); // 3
Diagnostic(ErrorCode.ERR_RefReadonlyNotField, "F").WithArguments("field", "F").WithLocation(18, 20),
// (19,20): error CS8329: Cannot use field 'F' as a ref or out value because it is a readonly variable
// M3(out F); // 4
Diagnostic(ErrorCode.ERR_RefReadonlyNotField, "F").WithArguments("field", "F").WithLocation(19, 20),
// (27,16): error CS8329: Cannot use field 'F' as a ref or out value because it is a readonly variable
// M2(ref F); // 5
Diagnostic(ErrorCode.ERR_RefReadonlyNotField, "F").WithArguments("field", "F").WithLocation(27, 16),
// (28,16): error CS8329: Cannot use field 'F' as a ref or out value because it is a readonly variable
// M3(out F); // 6
Diagnostic(ErrorCode.ERR_RefReadonlyNotField, "F").WithArguments("field", "F").WithLocation(28, 16));
}
[Fact]
public void RefParameter_InstanceMethod_ReadonlyRef()
{
var source =
@"ref struct S<T>
{
public readonly ref T F;
public S(ref T t)
{
F = ref t;
M1(F);
M2(ref F);
M3(out F);
M4(F);
M4(in F);
}
object P
{
init
{
M1(F);
M2(ref F);
M3(out F);
M4(F);
M4(in F);
}
}
void M()
{
M1(F);
M2(ref F);
M3(out F);
M4(F);
M4(in F);
}
static void M1(T t) { }
static void M2(ref T t) { }
static void M3(out T t) { t = default; }
static void M4(in T t) { }
}";
var comp = CreateCompilation(new[] { source, IsExternalInitTypeDefinition }, targetFramework: TargetFramework.Net70);
comp.VerifyEmitDiagnostics();
}
[Fact]
public void RefParameter_InstanceMethod_ReadonlyRefReadonly()
{
var source =
@"ref struct S<T>
{
public readonly ref readonly T F;
public S(ref T t)
{
F = ref t;
M1(F);
M2(ref F); // 1
M3(out F); // 2
M4(F);
M4(in F);
}
object P
{
init
{
M1(F);
M2(ref F); // 3
M3(out F); // 4
M4(F);
M4(in F);
}
}
void M()
{
M1(F);
M2(ref F); // 5
M3(out F); // 6
M4(F);
M4(in F);
}
static void M1(T t) { }
static void M2(ref T t) { }
static void M3(out T t) { t = default; }
static void M4(in T t) { }
}";
var comp = CreateCompilation(new[] { source, IsExternalInitTypeDefinition }, targetFramework: TargetFramework.Net70);
comp.VerifyEmitDiagnostics(
// (8,16): error CS8329: Cannot use field 'F' as a ref or out value because it is a readonly variable
// M2(ref F); // 1
Diagnostic(ErrorCode.ERR_RefReadonlyNotField, "F").WithArguments("field", "F").WithLocation(8, 16),
// (9,16): error CS8329: Cannot use field 'F' as a ref or out value because it is a readonly variable
// M3(out F); // 2
Diagnostic(ErrorCode.ERR_RefReadonlyNotField, "F").WithArguments("field", "F").WithLocation(9, 16),
// (18,20): error CS8329: Cannot use field 'F' as a ref or out value because it is a readonly variable
// M2(ref F); // 3
Diagnostic(ErrorCode.ERR_RefReadonlyNotField, "F").WithArguments("field", "F").WithLocation(18, 20),
// (19,20): error CS8329: Cannot use field 'F' as a ref or out value because it is a readonly variable
// M3(out F); // 4
Diagnostic(ErrorCode.ERR_RefReadonlyNotField, "F").WithArguments("field", "F").WithLocation(19, 20),
// (27,16): error CS8329: Cannot use field 'F' as a ref or out value because it is a readonly variable
// M2(ref F); // 5
Diagnostic(ErrorCode.ERR_RefReadonlyNotField, "F").WithArguments("field", "F").WithLocation(27, 16),
// (28,16): error CS8329: Cannot use field 'F' as a ref or out value because it is a readonly variable
// M3(out F); // 6
Diagnostic(ErrorCode.ERR_RefReadonlyNotField, "F").WithArguments("field", "F").WithLocation(28, 16));
}
[Fact]
public void RefParameter_Ref()
{
var source =
@"ref struct S<T>
{
public ref T F;
}
class Program
{
static void M1<T>(T t) { }
static void M2<T>(ref T t) { }
static void M3<T>(out T t) { t = default; }
static void M4<T>(in T t) { }
static void FromValue1<T>(S<T> s) { M1(s.F); }
static void FromValue2<T>(S<T> s) { M2(ref s.F); }
static void FromValue3<T>(S<T> s) { M3(out s.F); }
static void FromValue4A<T>(S<T> s) { M4(in s.F); }
static void FromValue4B<T>(S<T> s) { M4(s.F); }
static void FromRef1<T>(ref S<T> s) { M1(s.F); }
static void FromRef2<T>(ref S<T> s) { M2(ref s.F); }
static void FromRef3<T>(ref S<T> s) { M3(out s.F); }
static void FromRef4A<T>(ref S<T> s) { M4(in s.F); }
static void FromRef4B<T>(ref S<T> s) { M4(s.F); }
static void FromOut1<T>(out S<T> s) { s = default; M1(s.F); }
static void FromOut2<T>(out S<T> s) { s = default; M2(ref s.F); }
static void FromOut3<T>(out S<T> s) { s = default; M3(out s.F); }
static void FromOut4A<T>(out S<T> s) { s = default; M4(in s.F); }
static void FromOut4B<T>(out S<T> s) { s = default; M4(s.F); }
static void FromIn1<T>(in S<T> s) { M1(s.F); }
static void FromIn2<T>(in S<T> s) { M2(ref s.F); }
static void FromIn3<T>(in S<T> s) { M3(out s.F); }
static void FromIn4A<T>(in S<T> s) { M4(in s.F); }
static void FromIn4B<T>(in S<T> s) { M4(s.F); }
}";
var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70);
comp.VerifyEmitDiagnostics();
}
[Fact]
public void RefParameter_RefReadonly()
{
var source =
@"ref struct S<T>
{
public ref readonly T F;
}
class Program
{
static void M1<T>(T t) { }
static void M2<T>(ref T t) { }
static void M3<T>(out T t) { t = default; }
static void M4<T>(in T t) { }
static void FromValue1<T>(S<T> s) { M1(s.F); }
static void FromValue2<T>(S<T> s) { M2(ref s.F); } // 1
static void FromValue3<T>(S<T> s) { M3(out s.F); } // 2
static void FromValue4A<T>(S<T> s) { M4(in s.F); }
static void FromValue4B<T>(S<T> s) { M4(s.F); }
static void FromRef1<T>(ref S<T> s) { M1(s.F); }
static void FromRef2<T>(ref S<T> s) { M2(ref s.F); } // 3
static void FromRef3<T>(ref S<T> s) { M3(out s.F); } // 4
static void FromRef4A<T>(ref S<T> s) { M4(in s.F); }
static void FromRef4B<T>(ref S<T> s) { M4(s.F); }
static void FromOut1<T>(out S<T> s) { s = default; M1(s.F); }
static void FromOut2<T>(out S<T> s) { s = default; M2(ref s.F); } // 5
static void FromOut3<T>(out S<T> s) { s = default; M3(out s.F); } // 6
static void FromOut4A<T>(out S<T> s) { s = default; M4(in s.F); }
static void FromOut4B<T>(out S<T> s) { s = default; M4(s.F); }
static void FromIn1<T>(in S<T> s) { M1(s.F); }
static void FromIn2<T>(in S<T> s) { M2(ref s.F); } // 7
static void FromIn3<T>(in S<T> s) { M3(out s.F); } // 8
static void FromIn4A<T>(in S<T> s) { M4(in s.F); }
static void FromIn4B<T>(in S<T> s) { M4(s.F); }
}";
var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70);
comp.VerifyEmitDiagnostics(
// (14,49): error CS8329: Cannot use field 'F' as a ref or out value because it is a readonly variable
// static void FromValue2<T>(S<T> s) { M2(ref s.F); } // 1
Diagnostic(ErrorCode.ERR_RefReadonlyNotField, "s.F").WithArguments("field", "F").WithLocation(14, 49),
// (15,49): error CS8329: Cannot use field 'F' as a ref or out value because it is a readonly variable
// static void FromValue3<T>(S<T> s) { M3(out s.F); } // 2
Diagnostic(ErrorCode.ERR_RefReadonlyNotField, "s.F").WithArguments("field", "F").WithLocation(15, 49),
// (20,51): error CS8329: Cannot use field 'F' as a ref or out value because it is a readonly variable
// static void FromRef2<T>(ref S<T> s) { M2(ref s.F); } // 3
Diagnostic(ErrorCode.ERR_RefReadonlyNotField, "s.F").WithArguments("field", "F").WithLocation(20, 51),
// (21,51): error CS8329: Cannot use field 'F' as a ref or out value because it is a readonly variable
// static void FromRef3<T>(ref S<T> s) { M3(out s.F); } // 4
Diagnostic(ErrorCode.ERR_RefReadonlyNotField, "s.F").WithArguments("field", "F").WithLocation(21, 51),
// (26,64): error CS8329: Cannot use field 'F' as a ref or out value because it is a readonly variable
// static void FromOut2<T>(out S<T> s) { s = default; M2(ref s.F); } // 5
Diagnostic(ErrorCode.ERR_RefReadonlyNotField, "s.F").WithArguments("field", "F").WithLocation(26, 64),
// (27,64): error CS8329: Cannot use field 'F' as a ref or out value because it is a readonly variable
// static void FromOut3<T>(out S<T> s) { s = default; M3(out s.F); } // 6
Diagnostic(ErrorCode.ERR_RefReadonlyNotField, "s.F").WithArguments("field", "F").WithLocation(27, 64),
// (32,49): error CS8329: Cannot use field 'F' as a ref or out value because it is a readonly variable
// static void FromIn2<T>(in S<T> s) { M2(ref s.F); } // 7
Diagnostic(ErrorCode.ERR_RefReadonlyNotField, "s.F").WithArguments("field", "F").WithLocation(32, 49),
// (33,49): error CS8329: Cannot use field 'F' as a ref or out value because it is a readonly variable
// static void FromIn3<T>(in S<T> s) { M3(out s.F); } // 8
Diagnostic(ErrorCode.ERR_RefReadonlyNotField, "s.F").WithArguments("field", "F").WithLocation(33, 49));
}
[Fact]
public void RefParameter_ReadonlyRef()
{
var source =
@"ref struct S<T>
{
public readonly ref T F;
}
class Program
{
static void M1<T>(T t) { }
static void M2<T>(ref T t) { }
static void M3<T>(out T t) { t = default; }
static void M4<T>(in T t) { }
static void FromValue1<T>(S<T> s) { M1(s.F); }
static void FromValue2<T>(S<T> s) { M2(ref s.F); }
static void FromValue3<T>(S<T> s) { M3(out s.F); }
static void FromValue4A<T>(S<T> s) { M4(in s.F); }
static void FromValue4B<T>(S<T> s) { M4(s.F); }
static void FromRef1<T>(ref S<T> s) { M1(s.F); }
static void FromRef2<T>(ref S<T> s) { M2(ref s.F); }
static void FromRef3<T>(ref S<T> s) { M3(out s.F); }
static void FromRef4A<T>(ref S<T> s) { M4(in s.F); }
static void FromRef4B<T>(ref S<T> s) { M4(s.F); }
static void FromOut1<T>(out S<T> s) { s = default; M1(s.F); }
static void FromOut2<T>(out S<T> s) { s = default; M2(ref s.F); }
static void FromOut3<T>(out S<T> s) { s = default; M3(out s.F); }
static void FromOut4A<T>(out S<T> s) { s = default; M4(in s.F); }
static void FromOut4B<T>(out S<T> s) { s = default; M4(s.F); }
static void FromIn1<T>(in S<T> s) { M1(s.F); }
static void FromIn2<T>(in S<T> s) { M2(ref s.F); }
static void FromIn3<T>(in S<T> s) { M3(out s.F); }
static void FromIn4A<T>(in S<T> s) { M4(in s.F); }
static void FromIn4B<T>(in S<T> s) { M4(s.F); }
}";
var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70);
comp.VerifyEmitDiagnostics();
}
[Fact]
public void RefParameter_ReadonlyRefReadonly()
{
var source =
@"ref struct S<T>
{
public readonly ref readonly T F;
}
class Program
{
static void M1<T>(T t) { }
static void M2<T>(ref T t) { }
static void M3<T>(out T t) { t = default; }
static void M4<T>(in T t) { }
static void FromValue1<T>(S<T> s) { M1(s.F); }
static void FromValue2<T>(S<T> s) { M2(ref s.F); } // 1
static void FromValue3<T>(S<T> s) { M3(out s.F); } // 2
static void FromValue4A<T>(S<T> s) { M4(in s.F); }
static void FromValue4B<T>(S<T> s) { M4(s.F); }
static void FromRef1<T>(ref S<T> s) { M1(s.F); }
static void FromRef2<T>(ref S<T> s) { M2(ref s.F); } // 3
static void FromRef3<T>(ref S<T> s) { M3(out s.F); } // 4
static void FromRef4A<T>(ref S<T> s) { M4(in s.F); }
static void FromRef4B<T>(ref S<T> s) { M4(s.F); }
static void FromOut1<T>(out S<T> s) { s = default; M1(s.F); }
static void FromOut2<T>(out S<T> s) { s = default; M2(ref s.F); } // 5
static void FromOut3<T>(out S<T> s) { s = default; M3(out s.F); } // 6
static void FromOut4A<T>(out S<T> s) { s = default; M4(in s.F); }
static void FromOut4B<T>(out S<T> s) { s = default; M4(s.F); }
static void FromIn1<T>(in S<T> s) { M1(s.F); }
static void FromIn2<T>(in S<T> s) { M2(ref s.F); } // 7
static void FromIn3<T>(in S<T> s) { M3(out s.F); } // 8
static void FromIn4A<T>(in S<T> s) { M4(in s.F); }
static void FromIn4B<T>(in S<T> s) { M4(s.F); }
}";
var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70);
comp.VerifyEmitDiagnostics(
// (14,49): error CS8329: Cannot use field 'F' as a ref or out value because it is a readonly variable
// static void FromValue2<T>(S<T> s) { M2(ref s.F); } // 1
Diagnostic(ErrorCode.ERR_RefReadonlyNotField, "s.F").WithArguments("field", "F").WithLocation(14, 49),
// (15,49): error CS8329: Cannot use field 'F' as a ref or out value because it is a readonly variable
// static void FromValue3<T>(S<T> s) { M3(out s.F); } // 2
Diagnostic(ErrorCode.ERR_RefReadonlyNotField, "s.F").WithArguments("field", "F").WithLocation(15, 49),
// (20,51): error CS8329: Cannot use field 'F' as a ref or out value because it is a readonly variable
// static void FromRef2<T>(ref S<T> s) { M2(ref s.F); } // 3
Diagnostic(ErrorCode.ERR_RefReadonlyNotField, "s.F").WithArguments("field", "F").WithLocation(20, 51),
// (21,51): error CS8329: Cannot use field 'F' as a ref or out value because it is a readonly variable
// static void FromRef3<T>(ref S<T> s) { M3(out s.F); } // 4
Diagnostic(ErrorCode.ERR_RefReadonlyNotField, "s.F").WithArguments("field", "F").WithLocation(21, 51),
// (26,64): error CS8329: Cannot use field 'F' as a ref or out value because it is a readonly variable
// static void FromOut2<T>(out S<T> s) { s = default; M2(ref s.F); } // 5
Diagnostic(ErrorCode.ERR_RefReadonlyNotField, "s.F").WithArguments("field", "F").WithLocation(26, 64),
// (27,64): error CS8329: Cannot use field 'F' as a ref or out value because it is a readonly variable
// static void FromOut3<T>(out S<T> s) { s = default; M3(out s.F); } // 6
Diagnostic(ErrorCode.ERR_RefReadonlyNotField, "s.F").WithArguments("field", "F").WithLocation(27, 64),
// (32,49): error CS8329: Cannot use field 'F' as a ref or out value because it is a readonly variable
// static void FromIn2<T>(in S<T> s) { M2(ref s.F); } // 7
Diagnostic(ErrorCode.ERR_RefReadonlyNotField, "s.F").WithArguments("field", "F").WithLocation(32, 49),
// (33,49): error CS8329: Cannot use field 'F' as a ref or out value because it is a readonly variable
// static void FromIn3<T>(in S<T> s) { M3(out s.F); } // 8
Diagnostic(ErrorCode.ERR_RefReadonlyNotField, "s.F").WithArguments("field", "F").WithLocation(33, 49));
}
[Fact]
public void RefParameter_ReadonlyRefReadonly_PEVerifyCompat()
{
var source =
@"#pragma warning disable 649
ref struct S<T>
{
public readonly ref readonly T F;
}
class Program
{
static void M1<T>(T t) { }
static void M4<T>(in T t) { }
static void FromValue1<T>(S<T> s) { M1(s.F); }
static void FromValue4A<T>(S<T> s) { M4(in s.F); }
static void FromValue4B<T>(S<T> s) { M4(s.F); }
static void FromRef1<T>(ref S<T> s) { M1(s.F); }
static void FromRef4A<T>(ref S<T> s) { M4(in s.F); }
static void FromRef4B<T>(ref S<T> s) { M4(s.F); }
static void FromOut1<T>(out S<T> s) { s = default; M1(s.F); }
static void FromOut4A<T>(out S<T> s) { s = default; M4(in s.F); }
static void FromOut4B<T>(out S<T> s) { s = default; M4(s.F); }
static void FromIn1<T>(in S<T> s) { M1(s.F); }
static void FromIn4A<T>(in S<T> s) { M4(in s.F); }
static void FromIn4B<T>(in S<T> s) { M4(s.F); }
}";
var comp = CreateCompilation(source, parseOptions: TestOptions.RegularPreview.WithFeature("peverify-compat"), targetFramework: TargetFramework.Net70);
comp.VerifyEmitDiagnostics();
}
[Fact]
public void InitobjField()
{
var source =
@"using System;
struct S<T>
{
public T F;
}
ref struct R<T>
{
public ref S<T> S;
}
class Program
{
static void Main()
{
var s = new S<int>();
scoped var r = new R<int>();
r.S = ref s;
NewField(ref r);
r.S.F = 42;
Console.WriteLine(s.F);
Console.WriteLine(r.S.F);
}
static void NewField<T>(ref R<T> r)
{
r.S = new S<T>();
}
}";
var comp = CreateCompilation(source, options: TestOptions.ReleaseExe, targetFramework: TargetFramework.Net70);
var verifier = CompileAndVerify(comp, verify: Verification.Skipped, expectedOutput: IncludeExpectedOutput(
@"42
42
"));
verifier.VerifyIL("Program.NewField<T>",
@"{
// Code size 13 (0xd)
.maxstack 1
IL_0000: ldarg.0
IL_0001: ldfld ""ref S<T> R<T>.S""
IL_0006: initobj ""S<T>""
IL_000c: ret
}");
}
[Fact]
public void ReadWriteField()
{
var source =
@"using System;
ref struct S<T>
{
public ref T F;
public S(ref T t) { F = ref t; }
}
class Program
{
static void Main()
{
int x = 1;
scoped var s = new S<int>();
s.F = ref x;
Write(s, 42);
Console.WriteLine(Read(s));
Console.WriteLine(x);
}
static int Read(S<int> s)
{
return s.F;
}
static void Write(S<int> s, int value)
{
s.F = value;
}
}";
var comp = CreateCompilation(source, options: TestOptions.ReleaseExe, targetFramework: TargetFramework.Net70);
var verifier = CompileAndVerify(comp, verify: Verification.Skipped, expectedOutput: IncludeExpectedOutput(
@"42
42
"));
verifier.VerifyIL("S<T>..ctor(ref T)",
@"{
// Code size 8 (0x8)
.maxstack 2
IL_0000: ldarg.0
IL_0001: ldarg.1
IL_0002: stfld ""ref T S<T>.F""
IL_0007: ret
}");
verifier.VerifyIL("Program.Read",
@"{
// Code size 8 (0x8)
.maxstack 1
IL_0000: ldarg.0
IL_0001: ldfld ""ref int S<int>.F""
IL_0006: ldind.i4
IL_0007: ret
}");
verifier.VerifyIL("Program.Write",
@"{
// Code size 9 (0x9)
.maxstack 2
IL_0000: ldarg.0
IL_0001: ldfld ""ref int S<int>.F""
IL_0006: ldarg.1
IL_0007: stind.i4
IL_0008: ret
}");
}
[Fact]
public void ReadWriteNestedField()
{
var source =
@"using System;
using System.Diagnostics.CodeAnalysis;
ref struct R1<T>
{
public ref T F;
public R1(ref T t) { F = ref t; }
}
ref struct R2<T>
{
public ref R1<T> R1;
public R2(ref R1<T> r1) { R1 = ref r1; }
}
class Program
{
static void Main()
{
int i = 0;
var r1 = new R1<int>(ref i);
var r2 = new R2<int>(ref r1);
r2.R1.F = 42;
Console.WriteLine(Read(r2));
Console.WriteLine(ReadIn(r2));
Console.WriteLine(i);
}
static T Read<T>(R2<T> r2)
{
return r2.R1.F;
}
static T ReadIn<T>(in R2<T> r2In)
{
return r2In.R1.F;
}
}";
var comp = CreateCompilation(new[] { source, UnscopedRefAttributeDefinition }, targetFramework: TargetFramework.Net70);
comp.VerifyEmitDiagnostics(
// (10,12): error CS9050: A ref field cannot refer to a ref struct.
// public ref R1<T> R1;
Diagnostic(ErrorCode.ERR_RefFieldCannotReferToRefStruct, "ref R1<T>").WithLocation(10, 12));
}
[Fact]
public void ReadWriteFieldWithTemp()
{
var source =
@"ref struct S<T>
{
public ref T F;
private int _other;
public S(int other) : this() { _other = other; }
}
class Program
{
static T ReadWrite1<T>(ref T t)
{
return new S<T>().F = ref t;
}
static T ReadWrite2<T>(ref T t)
{
return new S<T>(1).F = ref t;
}
}";
var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70);
comp.VerifyDiagnostics(
// (11,16): error CS0131: The left-hand side of an assignment must be a variable, property or indexer
// return new S<T>().F = ref t;
Diagnostic(ErrorCode.ERR_AssgLvalueExpected, "new S<T>().F").WithLocation(11, 16),
// (15,16): error CS0131: The left-hand side of an assignment must be a variable, property or indexer
// return new S<T>(1).F = ref t;
Diagnostic(ErrorCode.ERR_AssgLvalueExpected, "new S<T>(1).F").WithLocation(15, 16));
}
[WorkItem(62122, "https://github.com/dotnet/roslyn/issues/62122")]
[Fact]
public void ReadAndDiscard()
{
var source =
@"using System;
ref struct S<T>
{
public ref T F;
public S(ref T t) { F = ref t; }
}
class Program
{
static void Main()
{
int i = 1;
Try(1, () => ReadAndDiscard1(ref i));
Try(2, () => ReadAndDiscardNoArg<int>());
Try(3, () => ReadAndDiscard2(new S<int>(ref i)));
Try(4, () => ReadAndDiscard2(new S<int>()));
void Try(int i, Action a)
{
try
{
a();
Console.WriteLine(i);
}
catch (NullReferenceException)
{
Console.WriteLine(""NullReferenceException"");
}
}
}
static void ReadAndDiscard1<T>(ref T t)
{
_ = new S<T>(ref t).F;
}
static void ReadAndDiscardNoArg<T>()
{
_ = new S<T>().F;
}
static void ReadAndDiscard2<T>(in S<T> s)
{
_ = s.F;
}
}";
var comp = CreateCompilation(source, options: TestOptions.ReleaseExe, targetFramework: TargetFramework.Net70);
var verifier = CompileAndVerify(comp, verify: Verification.Skipped, expectedOutput: IncludeExpectedOutput(
@"1
NullReferenceException
3
NullReferenceException
"));
verifier.VerifyIL("Program.ReadAndDiscard1<T>", """
{
// Code size 18 (0x12)
.maxstack 1
IL_0000: ldarg.0
IL_0001: newobj "S<T>..ctor(ref T)"
IL_0006: ldfld "ref T S<T>.F"
IL_000b: ldobj "T"
IL_0010: pop
IL_0011: ret
}
""");
verifier.VerifyIL("Program.ReadAndDiscardNoArg<T>", """
{
// Code size 21 (0x15)
.maxstack 1
.locals init (S<T> V_0)
IL_0000: ldloca.s V_0
IL_0002: initobj "S<T>"
IL_0008: ldloc.0
IL_0009: ldfld "ref T S<T>.F"
IL_000e: ldobj "T"
IL_0013: pop
IL_0014: ret
}
""");
verifier.VerifyIL("Program.ReadAndDiscard2<T>", """
{
// Code size 13 (0xd)
.maxstack 1
IL_0000: ldarg.0
IL_0001: ldfld "ref T S<T>.F"
IL_0006: ldobj "T"
IL_000b: pop
IL_000c: ret
}
""");
}
[Fact]
public void RefReturn_ByValueArg()
{
var source =
@"using System;
ref struct S<T>
{
public ref T F;
public S(ref T t) { F = ref t; }
}
class Program
{
static void Main()
{
int i = 1;
var s = new S<int>(ref i);
RefReturn(s) = 2;
i = RefReadonlyReturn(s);
Console.WriteLine(i);
}
static ref T RefReturn<T>(S<T> s) => ref s.F;
static ref readonly T RefReadonlyReturn<T>(S<T> s) => ref s.F;
}";
var comp = CreateCompilation(source, options: TestOptions.ReleaseExe, targetFramework: TargetFramework.Net70);
var verifier = CompileAndVerify(comp, verify: Verification.Skipped, expectedOutput: IncludeExpectedOutput("2"));
var expectedIL =
@"{
// Code size 8 (0x8)
.maxstack 1
IL_0000: ldarga.s V_0
IL_0002: ldfld ""ref T S<T>.F""
IL_0007: ret
}";
verifier.VerifyIL("Program.RefReturn<T>", expectedIL);
verifier.VerifyIL("Program.RefReadonlyReturn<T>", expectedIL);
}
[Fact]
public void RefReturn_RefArg()
{
var source =
@"using System;
ref struct S<T>
{
public ref T F;
public S(ref T t) { F = ref t; }
}
class Program
{
static void Main()
{
int i = 1;
var s = new S<int>(ref i);
RefReturn(ref s) = 2;
i = RefReadonlyReturn(ref s);
Console.WriteLine(i);
}
static ref T RefReturn<T>(ref S<T> s) => ref s.F;
static ref readonly T RefReadonlyReturn<T>(ref S<T> s) => ref s.F;
}";
var comp = CreateCompilation(source, options: TestOptions.ReleaseExe, targetFramework: TargetFramework.Net70);
var verifier = CompileAndVerify(comp, verify: Verification.Skipped, expectedOutput: IncludeExpectedOutput("2"));
var expectedIL =
@"{
// Code size 7 (0x7)
.maxstack 1
IL_0000: ldarg.0
IL_0001: ldfld ""ref T S<T>.F""
IL_0006: ret
}";
verifier.VerifyIL("Program.RefReturn<T>", expectedIL);
verifier.VerifyIL("Program.RefReadonlyReturn<T>", expectedIL);
}
[Fact]
public void RefReturn_InArg()
{
var source =
@"using System;
ref struct S<T>
{
public ref T F;
public S(ref T t) { F = ref t; }
}
class Program
{
static void Main()
{
int i = 1;
var s = new S<int>(ref i);
RefReturn(s) = 2;
i = RefReadonlyReturn(s);
Console.WriteLine(i);
}
static ref T RefReturn<T>(in S<T> s) => ref s.F;
static ref readonly T RefReadonlyReturn<T>(in S<T> s) => ref s.F;
}";
var comp = CreateCompilation(source, options: TestOptions.ReleaseExe, targetFramework: TargetFramework.Net70);
var verifier = CompileAndVerify(comp, verify: Verification.Skipped, expectedOutput: IncludeExpectedOutput("2"));
var expectedIL =
@"{
// Code size 7 (0x7)
.maxstack 1
IL_0000: ldarg.0
IL_0001: ldfld ""ref T S<T>.F""
IL_0006: ret
}";
verifier.VerifyIL("Program.RefReturn<T>", expectedIL);
verifier.VerifyIL("Program.RefReadonlyReturn<T>", expectedIL);
}
[Fact]
public void RefReturn_OutArg()
{
var source =
@"using System;
ref struct S<T>
{
public ref T F;
public S(ref T t) { F = ref t; }
}
class Program
{
static void Main()
{
int i = 1;
scoped S<int> s;
RefReturn(out s, ref i) = 2;
i = RefReadonlyReturn(out s, ref i);
Console.WriteLine(i);
}
static ref T RefReturn<T>(out S<T> s, ref T t)
{
s = new S<T>(ref t);
return ref s.F;
}
static ref readonly T RefReadonlyReturn<T>(out S<T> s, ref T t)
{
s = new S<T>(ref t);
return ref s.F;
}
}";
var comp = CreateCompilation(source, options: TestOptions.ReleaseExe, targetFramework: TargetFramework.Net70);
var verifier = CompileAndVerify(comp, verify: Verification.Skipped, expectedOutput: IncludeExpectedOutput("2"));
var expectedIL =
@"{
// Code size 19 (0x13)
.maxstack 2
IL_0000: ldarg.0
IL_0001: ldarg.1
IL_0002: newobj ""S<T>..ctor(ref T)""
IL_0007: stobj ""S<T>""
IL_000c: ldarg.0
IL_000d: ldfld ""ref T S<T>.F""
IL_0012: ret
}";
verifier.VerifyIL("Program.RefReturn<T>", expectedIL);
verifier.VerifyIL("Program.RefReadonlyReturn<T>", expectedIL);
}
[Fact]
public void CompoundOperations_01()
{
var source =
@"using System;
ref struct S<T>
{
public ref T F;
public S(ref T t) { F = ref t; }
}
class Program
{
static void Main()
{
int x = 42;
scoped var s = new S<int>(ref x);
Increment(s);
Console.WriteLine(s.F);
Console.WriteLine(x);
Subtract(s, 10);
Console.WriteLine(s.F);
Console.WriteLine(x);
}
static void Increment(S<int> s)
{
s.F++;
}
static void Subtract(S<int> s, int offset)
{
s.F -= offset;
}
}";
var comp = CreateCompilation(source, options: TestOptions.ReleaseExe, targetFramework: TargetFramework.Net70);
var verifier = CompileAndVerify(comp, verify: Verification.Skipped, expectedOutput: IncludeExpectedOutput(
@"43
43
33
33
"));
verifier.VerifyIL("Program.Increment",
@"{
// Code size 13 (0xd)
.maxstack 3
IL_0000: ldarga.s V_0
IL_0002: ldfld ""ref int S<int>.F""
IL_0007: dup
IL_0008: ldind.i4
IL_0009: ldc.i4.1
IL_000a: add
IL_000b: stind.i4
IL_000c: ret
}");
verifier.VerifyIL("Program.Subtract",
@"{
// Code size 13 (0xd)
.maxstack 3
IL_0000: ldarga.s V_0
IL_0002: ldfld ""ref int S<int>.F""
IL_0007: dup
IL_0008: ldind.i4
IL_0009: ldarg.1
IL_000a: sub
IL_000b: stind.i4
IL_000c: ret
}");
}
[Theory]
[InlineData("ref")]
[InlineData("readonly ref")]
public void CompoundOperations_02(string refKind)
{
var source =
$@"using System;
ref struct S
{{
public {refKind} int F;
public S(ref int i) {{ F = ref i; }}
public void Increment()
{{
F++;
}}
public void Subtract(int offset)
{{
F -= offset;
}}
}}
class Program
{{
static void Main()
{{
int x = 42;
scoped var s = new S(ref x);
s.Increment();
Console.WriteLine(s.F);
Console.WriteLine(x);
s.Subtract(10);
Console.WriteLine(s.F);
Console.WriteLine(x);
}}
}}";
var comp = CreateCompilation(source, options: TestOptions.ReleaseExe, targetFramework: TargetFramework.Net70);
var verifier = CompileAndVerify(comp, verify: Verification.Skipped, expectedOutput: IncludeExpectedOutput(
@"43
43
33
33
"));
verifier.VerifyIL("S.Increment",
@"{
// Code size 17 (0x11)
.maxstack 3
IL_0000: ldarg.0
IL_0001: ldfld ""ref int S.F""
IL_0006: ldarg.0
IL_0007: ldfld ""ref int S.F""
IL_000c: ldind.i4
IL_000d: ldc.i4.1
IL_000e: add
IL_000f: stind.i4
IL_0010: ret
}");
verifier.VerifyIL("S.Subtract",
@"{
// Code size 17 (0x11)
.maxstack 3
IL_0000: ldarg.0
IL_0001: ldfld ""ref int S.F""
IL_0006: ldarg.0
IL_0007: ldfld ""ref int S.F""
IL_000c: ldind.i4
IL_000d: ldarg.1
IL_000e: sub
IL_000f: stind.i4
IL_0010: ret
}");
}
[Fact]
public void ConditionalOperator()
{
var source =
@"using System;
ref struct S<T>
{
public ref T F;
public S(ref T t) { F = ref t; }
}
class Program
{
static void Main()
{
int x = 1;
int y = 2;
var sx = new S<int>(ref x);
var sy = new S<int>(ref y);
Console.WriteLine(ConditionalOperator(true, sx, sy));
Console.WriteLine(ConditionalOperator(false, sx, sy));
ConditionalOperatorRef(true, ref sx, ref sy) = 3;
ConditionalOperatorRef(false, ref sx, ref sy) = 4;
Console.WriteLine(x);
Console.WriteLine(y);
}
static T ConditionalOperator<T>(bool b, S<T> sx, S<T> sy)
{
return b ? sx.F : sy.F;
}
static ref T ConditionalOperatorRef<T>(bool b, ref S<T> sx, ref S<T> sy)
{
return ref b ? ref sx.F : ref sy.F;
}
}";
var comp = CreateCompilation(source, options: TestOptions.ReleaseExe, targetFramework: TargetFramework.Net70);
var verifier = CompileAndVerify(comp, verify: Verification.Skipped, expectedOutput: IncludeExpectedOutput(
@"1
2
3
4
"));
verifier.VerifyIL("Program.ConditionalOperator<T>",
@"{
// Code size 27 (0x1b)
.maxstack 1
IL_0000: ldarg.0
IL_0001: brtrue.s IL_000f
IL_0003: ldarg.2
IL_0004: ldfld ""ref T S<T>.F""
IL_0009: ldobj ""T""
IL_000e: ret
IL_000f: ldarg.1
IL_0010: ldfld ""ref T S<T>.F""
IL_0015: ldobj ""T""
IL_001a: ret
}");
verifier.VerifyIL("Program.ConditionalOperatorRef<T>",
@"{
// Code size 17 (0x11)
.maxstack 1
IL_0000: ldarg.0
IL_0001: brtrue.s IL_000a
IL_0003: ldarg.2
IL_0004: ldfld ""ref T S<T>.F""
IL_0009: ret
IL_000a: ldarg.1
IL_000b: ldfld ""ref T S<T>.F""
IL_0010: ret
}");
}
[Fact]
public void ConditionalAccess()
{
var source =
@"using System;
ref struct S<T>
{
public ref T F;
public S(ref T t) { F = ref t; }
}
class Program
{
static void Main()
{
object o = 1;
int i = 2;
var s1 = new S<object>(ref o);
var s2 = new S<int>(ref i);
Console.WriteLine(ConditionalAccess(s1));
Console.WriteLine(ConditionalAccess(s2));
}
static string ConditionalAccess<T>(S<T> s)
{
return s.F?.ToString();
}
}";
var comp = CreateCompilation(source, options: TestOptions.ReleaseExe, targetFramework: TargetFramework.Net70);
var verifier = CompileAndVerify(comp, verify: Verification.Skipped, expectedOutput: IncludeExpectedOutput(
@"1
2
"));
verifier.VerifyIL("Program.ConditionalAccess<T>",
@"{
// Code size 54 (0x36)
.maxstack 2
.locals init (T V_0)
IL_0000: ldarga.s V_0
IL_0002: ldfld ""ref T S<T>.F""
IL_0007: ldloca.s V_0
IL_0009: initobj ""T""
IL_000f: ldloc.0
IL_0010: box ""T""
IL_0015: brtrue.s IL_002a
IL_0017: ldobj ""T""
IL_001c: stloc.0
IL_001d: ldloca.s V_0
IL_001f: ldloc.0
IL_0020: box ""T""
IL_0025: brtrue.s IL_002a
IL_0027: pop
IL_0028: ldnull
IL_0029: ret
IL_002a: constrained. ""T""
IL_0030: callvirt ""string object.ToString()""
IL_0035: ret
}");
}
[Fact]
public void Deconstruct()
{
var source =
@"using System;
class Pair<T, U>
{
public readonly T First;
public readonly U Second;
public Pair(T first, U second)
{
First = first;
Second = second;
}
public void Deconstruct(out T first, out U second)
{
first = First;
second = Second;
}
}
ref struct S<T>
{
public ref T F;
public S(ref T t) { F = ref t; }
}
class Program
{
static void Main()
{
int i = 0;
string s = null;
var s1 = new S<int>(ref i);
var s2 = new S<string>(ref s);
Deconstruct(new Pair<int, string>(1, ""Hello world""), s1, s2);
Console.WriteLine((i, s));
}
static void Deconstruct<T, U>(Pair<T, U> pair, S<T> s1, S<U> s2)
{
(s1.F, s2.F) = pair;
}
}";
var references = TargetFrameworkUtil.GetReferences(TargetFramework.Standard, additionalReferences: null);
var comp = CreateCompilation(source, options: TestOptions.ReleaseExe, targetFramework: TargetFramework.Net70);
var verifier = CompileAndVerify(comp, verify: Verification.Skipped, expectedOutput: IncludeExpectedOutput(@"(1, Hello world)"));
verifier.VerifyIL("Program.Deconstruct<T, U>",
@"{
// Code size 39 (0x27)
.maxstack 4
.locals init (T& V_0,
T V_1,
U V_2)
IL_0000: ldarga.s V_1
IL_0002: ldfld ""ref T S<T>.F""
IL_0007: stloc.0
IL_0008: ldarga.s V_2
IL_000a: ldfld ""ref U S<U>.F""
IL_000f: ldarg.0
IL_0010: ldloca.s V_1
IL_0012: ldloca.s V_2
IL_0014: callvirt ""void Pair<T, U>.Deconstruct(out T, out U)""
IL_0019: ldloc.0
IL_001a: ldloc.1
IL_001b: stobj ""T""
IL_0020: ldloc.2
IL_0021: stobj ""U""
IL_0026: ret
}");
}
[WorkItem(64448, "https://github.com/dotnet/roslyn/issues/64448")]
[Theory]
[InlineData(LanguageVersion.CSharp10)]
[InlineData(LanguageVersion.CSharp11)]
public void Deconstruct_01(LanguageVersion languageVersion)
{
var source =
@"ref struct R1
{
public R1(ref int i) { }
public void Deconstruct(out int x, out int y) => throw null;
}
readonly ref struct R2
{
public R2(ref int i) { }
public void Deconstruct(out int x, out int y) => throw null;
}
class Program
{
static void F1()
{
int i = 1;
var r = new R1(ref i);
int x1, y1;
(x1, y1) = r;
r.Deconstruct(out x1, out y1);
}
static void F2()
{
int i = 2;
var r = new R2(ref i);
int x2, y2;
(x2, y2) = r;
r.Deconstruct(out x2, out y2);
}
}";
var comp = CreateCompilation(source, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion));
comp.VerifyEmitDiagnostics();
}
[WorkItem(64448, "https://github.com/dotnet/roslyn/issues/64448")]
[Theory]
[InlineData(LanguageVersion.CSharp10)]
[InlineData(LanguageVersion.CSharp11)]
public void Deconstruct_02A(LanguageVersion languageVersion)
{
var source =
@"using System;
static class Program
{
static void Main()
{
Span<int> s = stackalloc int[10];
int x, y;
(x, y) = s;
s.Deconstruct(out x, out y);
}
static void Deconstruct(this Span<int> s, out int x, out int y) => throw null;
}";
var comp = CreateCompilationWithSpanAndMemoryExtensions(source, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion));
comp.VerifyEmitDiagnostics();
}
[WorkItem(64448, "https://github.com/dotnet/roslyn/issues/64448")]
[Theory]
[InlineData(LanguageVersion.CSharp10)]
[InlineData(LanguageVersion.CSharp11)]
public void Deconstruct_02B(LanguageVersion languageVersion)
{
var source =
@"using System;
static class Program
{
static void Main()
{
ReadOnlySpan<int> s = stackalloc int[10];
int x, y;
(x, y) = s;
s.Deconstruct(out x, out y);
}
static void Deconstruct(this ReadOnlySpan<int> s, out int x, out int y) => throw null;
}";
var comp = CreateCompilationWithSpanAndMemoryExtensions(source, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion));
comp.VerifyEmitDiagnostics();
}
[WorkItem(64448, "https://github.com/dotnet/roslyn/issues/64448")]
[Theory]
[InlineData(LanguageVersion.CSharp10)]
[InlineData(LanguageVersion.CSharp11)]
public void Deconstruct_03A(LanguageVersion languageVersion)
{
var source =
@"using System;
static class Program
{
static void F1()
{
Span<int> s = stackalloc int[10];
int x1;
Span<byte> y1;
(x1, y1) = s; // 1
s.Deconstruct(out x1, out y1); // 2
}
static void F2()
{
Span<int> s = stackalloc int[10];
int x2;
Span<byte> y2 = stackalloc byte[1];
(x2, y2) = s;
s.Deconstruct(out x2, out y2);
}
static void Deconstruct(this Span<int> s, out int x, out Span<byte> y) => throw null;
}";
var comp = CreateCompilationWithSpanAndMemoryExtensions(source, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion));
comp.VerifyEmitDiagnostics(
// (9,9): error CS8352: Cannot use variable '(x1, y1) = s' in this context because it may expose referenced variables outside of their declaration scope
// (x1, y1) = s; // 1
Diagnostic(ErrorCode.ERR_EscapeVariable, "(x1, y1) = s").WithArguments("(x1, y1) = s").WithLocation(9, 9),
// (9,20): error CS8350: This combination of arguments to 'Program.Deconstruct(Span<int>, out int, out Span<byte>)' is disallowed because it may expose variables referenced by parameter 's' outside of their declaration scope
// (x1, y1) = s; // 1
Diagnostic(ErrorCode.ERR_CallArgMixing, "s").WithArguments("Program.Deconstruct(System.Span<int>, out int, out System.Span<byte>)", "s").WithLocation(9, 20),
// (10,9): error CS8352: Cannot use variable 's' in this context because it may expose referenced variables outside of their declaration scope
// s.Deconstruct(out x1, out y1); // 2
Diagnostic(ErrorCode.ERR_EscapeVariable, "s").WithArguments("s").WithLocation(10, 9),
// (10,9): error CS8350: This combination of arguments to 'Program.Deconstruct(Span<int>, out int, out Span<byte>)' is disallowed because it may expose variables referenced by parameter 's' outside of their declaration scope
// s.Deconstruct(out x1, out y1); // 2
Diagnostic(ErrorCode.ERR_CallArgMixing, "s.Deconstruct(out x1, out y1)").WithArguments("Program.Deconstruct(System.Span<int>, out int, out System.Span<byte>)", "s").WithLocation(10, 9));
}
[WorkItem(64448, "https://github.com/dotnet/roslyn/issues/64448")]
[Theory]
[InlineData(LanguageVersion.CSharp10)]
[InlineData(LanguageVersion.CSharp11)]
public void Deconstruct_03B(LanguageVersion languageVersion)
{
var source =
@"using System;
static class Program
{
static void F1()
{
ReadOnlySpan<int> s = stackalloc int[10];
int x1;
ReadOnlySpan<byte> y1;
(x1, y1) = s; // 1
s.Deconstruct(out x1, out y1); // 2
}
static void F2()
{
ReadOnlySpan<int> s = stackalloc int[10];
int x2;
ReadOnlySpan<byte> y2 = stackalloc byte[1];
(x2, y2) = s;
s.Deconstruct(out x2, out y2);
}
static void Deconstruct(this ReadOnlySpan<int> s, out int x, out ReadOnlySpan<byte> y) => throw null;
}";
var comp = CreateCompilationWithSpanAndMemoryExtensions(source, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion));
comp.VerifyEmitDiagnostics(
// (9,9): error CS8352: Cannot use variable '(x1, y1) = s' in this context because it may expose referenced variables outside of their declaration scope
// (x1, y1) = s; // 1
Diagnostic(ErrorCode.ERR_EscapeVariable, "(x1, y1) = s").WithArguments("(x1, y1) = s").WithLocation(9, 9),
// (9,20): error CS8350: This combination of arguments to 'Program.Deconstruct(ReadOnlySpan<int>, out int, out ReadOnlySpan<byte>)' is disallowed because it may expose variables referenced by parameter 's' outside of their declaration scope
// (x1, y1) = s; // 1
Diagnostic(ErrorCode.ERR_CallArgMixing, "s").WithArguments("Program.Deconstruct(System.ReadOnlySpan<int>, out int, out System.ReadOnlySpan<byte>)", "s").WithLocation(9, 20),
// (10,9): error CS8352: Cannot use variable 's' in this context because it may expose referenced variables outside of their declaration scope
// s.Deconstruct(out x1, out y1); // 2
Diagnostic(ErrorCode.ERR_EscapeVariable, "s").WithArguments("s").WithLocation(10, 9),
// (10,9): error CS8350: This combination of arguments to 'Program.Deconstruct(ReadOnlySpan<int>, out int, out ReadOnlySpan<byte>)' is disallowed because it may expose variables referenced by parameter 's' outside of their declaration scope
// s.Deconstruct(out x1, out y1); // 2
Diagnostic(ErrorCode.ERR_CallArgMixing, "s.Deconstruct(out x1, out y1)").WithArguments("Program.Deconstruct(System.ReadOnlySpan<int>, out int, out System.ReadOnlySpan<byte>)", "s").WithLocation(10, 9));
}
[Theory]
[InlineData(LanguageVersion.CSharp10)]
[InlineData(LanguageVersion.CSharp11)]
public void Deconstruct_04(LanguageVersion languageVersion)
{
var source =
@"using System;
ref struct R1
{
public void Deconstruct(out R2 x, out R2 y) => throw null;
}
ref struct R2
{
public R2(Span<byte> s) { }
}
static class Program
{
static void Main()
{
Span<int> s = stackalloc int[10];
R2 x = new R2(stackalloc byte[1]);
R2 y = new R2(stackalloc byte[1]);
R2 z1 = new R2(stackalloc byte[1]);
(x, (y, z1)) = s;
R2 z2 = default;
(x, (y, z2)) = s; // 1
(z2, (y, z1)) = s; // 2
}
static void Deconstruct(this Span<int> s, out R2 x, out R1 y) => throw null;
}";
var comp = CreateCompilationWithSpanAndMemoryExtensions(source, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion));
comp.VerifyEmitDiagnostics(
// (20,9): error CS8352: Cannot use variable '(x, (y, z2)) = s' in this context because it may expose referenced variables outside of their declaration scope
// (x, (y, z2)) = s; // 1
Diagnostic(ErrorCode.ERR_EscapeVariable, "(x, (y, z2)) = s").WithArguments("(x, (y, z2)) = s").WithLocation(20, 9),
// (20,24): error CS8350: This combination of arguments to 'R1.Deconstruct(out R2, out R2)' is disallowed because it may expose variables referenced by parameter 'this' outside of their declaration scope
// (x, (y, z2)) = s; // 1
Diagnostic(ErrorCode.ERR_CallArgMixing, "s").WithArguments("R1.Deconstruct(out R2, out R2)", "this").WithLocation(20, 24),
// (21,9): error CS8352: Cannot use variable '(z2, (y, z1)) = s' in this context because it may expose referenced variables outside of their declaration scope
// (z2, (y, z1)) = s; // 2
Diagnostic(ErrorCode.ERR_EscapeVariable, "(z2, (y, z1)) = s").WithArguments("(z2, (y, z1)) = s").WithLocation(21, 9),
// (21,25): error CS8350: This combination of arguments to 'Program.Deconstruct(Span<int>, out R2, out R1)' is disallowed because it may expose variables referenced by parameter 's' outside of their declaration scope
// (z2, (y, z1)) = s; // 2
Diagnostic(ErrorCode.ERR_CallArgMixing, "s").WithArguments("Program.Deconstruct(System.Span<int>, out R2, out R1)", "s").WithLocation(21, 25));
}
[Theory]
[InlineData(LanguageVersion.CSharp10)]
[InlineData(LanguageVersion.CSharp11)]
public void Deconstruct_05(LanguageVersion languageVersion)
{
var source =
@"ref struct R
{
}
static class Program
{
static void F(ref R r)
{
(r, r) = r;
r.Deconstruct(out r, out r);
}
static void Deconstruct(this R r, out R x, out R y) => throw null;
}";
var comp = CreateCompilation(source, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion));
comp.VerifyEmitDiagnostics();
}
[Theory]
[InlineData(LanguageVersion.CSharp10)]
[InlineData(LanguageVersion.CSharp11)]
public void Deconstruct_06(LanguageVersion languageVersion)
{
var source =
@"using System;
static class Program
{
static void F()
{
Span<int> s = stackalloc int[10];
(s, s) = s;
s.Deconstruct(out s, out s);
}
static void Deconstruct(this Span<int> s, out Span<int> x, out Span<int> y) => throw null;
}";
var comp = CreateCompilationWithSpanAndMemoryExtensions(source, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion));
comp.VerifyEmitDiagnostics();
}
[WorkItem(64448, "https://github.com/dotnet/roslyn/issues/64448")]
[Fact]
public void Deconstruct_07()
{
var source =
@"ref struct R1
{
public R1(ref int i) { }
public void Deconstruct(out int x, out R2 y) => throw null;
}
ref struct R2
{
}
class Program
{
static void F1()
{
int i = 1;
var r = new R1(ref i);
int x;
scoped R2 y;
(x, y) = r;
r.Deconstruct(out x, out y);
}
}";
var comp = CreateCompilation(source);
comp.VerifyEmitDiagnostics();
}
[Theory]
[InlineData(LanguageVersion.CSharp10)]
[InlineData(LanguageVersion.CSharp11)]
public void Deconstruct_08(LanguageVersion languageVersion)
{
var source =
@"using System;
static class Program
{
static void Main()
{
Span<int> x = stackalloc int[10];
Span<int> y = default;
(x, y) = (y, x);
}
}";
var comp = CreateCompilationWithSpanAndMemoryExtensions(source, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion));
comp.VerifyEmitDiagnostics(
// (8,19): error CS0306: The type 'Span<int>' may not be used as a type argument
// (x, y) = (y, x);
Diagnostic(ErrorCode.ERR_BadTypeArgument, "y").WithArguments("System.Span<int>").WithLocation(8, 19),
// (8,22): error CS0306: The type 'Span<int>' may not be used as a type argument
// (x, y) = (y, x);
Diagnostic(ErrorCode.ERR_BadTypeArgument, "x").WithArguments("System.Span<int>").WithLocation(8, 22));
}
[Theory]
[InlineData(LanguageVersion.CSharp10)]
[InlineData(LanguageVersion.CSharp11)]
public void Deconstruct_09(LanguageVersion languageVersion)
{
var source =
@"ref struct R1
{
public R1(ref int i) { }
public void Deconstruct(out int x, out R2 y) => throw null;
}
ref struct R2
{
}
class Program
{
static R2 F1()
{
int i = 1;
var r = new R1(ref i);
var (x1, y1) = r;
return y1; // 1
}
static R2 F2()
{
int i = 2;
var r = new R1(ref i);
r.Deconstruct(out var x2, out var y2);
return y2; // 2
}
static R2 F3(ref int i)
{
var r = new R1(ref i);
var (x3, y3) = r;
return y3;
}
static R2 F4(ref int i)
{
var r = new R1(ref i);
r.Deconstruct(out var x4, out var y4);
return y4;
}
}";
var comp = CreateCompilation(source, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion));
if (languageVersion == LanguageVersion.CSharp10)
{
comp.VerifyEmitDiagnostics();
}
else
{
comp.VerifyEmitDiagnostics(
// (16,16): error CS8352: Cannot use variable 'y1' in this context because it may expose referenced variables outside of their declaration scope
// return y1; // 1
Diagnostic(ErrorCode.ERR_EscapeVariable, "y1").WithArguments("y1").WithLocation(16, 16),
// (23,16): error CS8352: Cannot use variable 'y2' in this context because it may expose referenced variables outside of their declaration scope
// return y2; // 2
Diagnostic(ErrorCode.ERR_EscapeVariable, "y2").WithArguments("y2").WithLocation(23, 16));
}
}
[Theory]
[InlineData(LanguageVersion.CSharp10)]
[InlineData(LanguageVersion.CSharp11)]
public void Deconstruct_10(LanguageVersion languageVersion)
{
var source =
@"using System;
static class Program
{
static Span<byte> F1()
{
Span<int> s = stackalloc int[10];
var (x1, y1) = s;
return y1; // 1
}
static Span<byte> F2()
{
Span<int> s = stackalloc int[10];
s.Deconstruct(out var x2, out var y2);
return y2; // 2
}
static Span<byte> F3()
{
Span<int> s = default;
var (x3, y3) = s;
return y3;
}
static Span<byte> F4()
{
Span<int> s = default;
s.Deconstruct(out var x4, out var y4);
return y4;
}
static void Deconstruct(this Span<int> s, out int x, out Span<byte> y) => throw null;
}";
var comp = CreateCompilationWithSpanAndMemoryExtensions(source, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion));
comp.VerifyEmitDiagnostics(
// (8,16): error CS8352: Cannot use variable 'y1' in this context because it may expose referenced variables outside of their declaration scope
// return y1; // 1
Diagnostic(ErrorCode.ERR_EscapeVariable, "y1").WithArguments("y1").WithLocation(8, 16),
// (14,16): error CS8352: Cannot use variable 'y2' in this context because it may expose referenced variables outside of their declaration scope
// return y2; // 2
Diagnostic(ErrorCode.ERR_EscapeVariable, "y2").WithArguments("y2").WithLocation(14, 16));
}
[Theory]
[InlineData(LanguageVersion.CSharp10)]
[InlineData(LanguageVersion.CSharp11)]
public void Deconstruct_11(LanguageVersion languageVersion)
{
var source =
@"using System;
ref struct R
{
}
ref struct Enumerable
{
public Enumerable(Span<int> s) { }
public Enumerator GetEnumerator() => default;
}
ref struct Enumerator
{
public bool MoveNext() => false;
public Span<int> Current => default;
}
static class Program
{
static R F1()
{
var e = new Enumerable(stackalloc int[10]);
foreach (var (x1, y1) in e)
return y1; // 1
return default;
}
static R F2(ref int i)
{
var e = new Enumerable(default);
foreach (var (x2, y2) in e)
return y2;
return default;
}
static void Deconstruct(this Span<int> s, out R x, out R y) => throw null;
}";
var comp = CreateCompilationWithSpanAndMemoryExtensions(source, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion));
comp.VerifyEmitDiagnostics(
// (21,20): error CS8352: Cannot use variable 'y1' in this context because it may expose referenced variables outside of their declaration scope
// return y1; // 1
Diagnostic(ErrorCode.ERR_EscapeVariable, "y1").WithArguments("y1").WithLocation(21, 20));
}
[Theory]
[InlineData(LanguageVersion.CSharp10)]
[InlineData(LanguageVersion.CSharp11)]
public void Deconstruct_12(LanguageVersion languageVersion)
{
var source =
@"using System;
ref struct R
{
}
static class Program
{
static R F1()
{
Span<int> span = stackalloc int[10];
R x1, y1;
(x1, y1) = span; // 1
return y1;
}
static R F2()
{
Span<int> span = stackalloc int[10];
var (x2, y2) = span;
return y2; // 2
}
static R F3()
{
Span<int> span = stackalloc int[10];
(var x3, var y3) = span;
return y3; // 3
}
static R F4()
{
Span<int> span = stackalloc int[10];
(R x4, R y4) = span;
return y4; // 4
}
static R F5()
{
Span<int> span = default;
var (x5, y5) = span;
return y5;
}
static void Deconstruct(this Span<int> s, out R x, out R y) => throw null;
}";
var comp = CreateCompilationWithSpanAndMemoryExtensions(source, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion));
comp.VerifyEmitDiagnostics(
// (11,9): error CS8352: Cannot use variable '(x1, y1) = span' in this context because it may expose referenced variables outside of their declaration scope
// (x1, y1) = span; // 1
Diagnostic(ErrorCode.ERR_EscapeVariable, "(x1, y1) = span").WithArguments("(x1, y1) = span").WithLocation(11, 9),
// (11,20): error CS8350: This combination of arguments to 'Program.Deconstruct(Span<int>, out R, out R)' is disallowed because it may expose variables referenced by parameter 's' outside of their declaration scope
// (x1, y1) = span; // 1
Diagnostic(ErrorCode.ERR_CallArgMixing, "span").WithArguments("Program.Deconstruct(System.Span<int>, out R, out R)", "s").WithLocation(11, 20),
// (18,16): error CS8352: Cannot use variable 'y2' in this context because it may expose referenced variables outside of their declaration scope
// return y2; // 2
Diagnostic(ErrorCode.ERR_EscapeVariable, "y2").WithArguments("y2").WithLocation(18, 16),
// (24,16): error CS8352: Cannot use variable 'y3' in this context because it may expose referenced variables outside of their declaration scope
// return y3; // 3
Diagnostic(ErrorCode.ERR_EscapeVariable, "y3").WithArguments("y3").WithLocation(24, 16),
// (30,16): error CS8352: Cannot use variable 'y4' in this context because it may expose referenced variables outside of their declaration scope
// return y4; // 4
Diagnostic(ErrorCode.ERR_EscapeVariable, "y4").WithArguments("y4").WithLocation(30, 16));
}
[Theory]
[InlineData(LanguageVersion.CSharp10)]
[InlineData(LanguageVersion.CSharp11)]
public void Deconstruct_13(LanguageVersion languageVersion)
{
var source =
@"using System;
ref struct R
{
}
static class Program
{
static void F()
{
Span<int> span = stackalloc int[10];
var (x1, y1) = span;
span.Deconstruct(out var x2, out var y2);
}
static void Deconstruct(this Span<int> s, out R x, out R y) => throw null;
}";
var comp = CreateCompilationWithSpanAndMemoryExtensions(source, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion));
comp.VerifyEmitDiagnostics();
}
[Fact]
public void InParamReorder()
{
var source =
@"using System;
using System.Diagnostics.CodeAnalysis;
ref struct S<T>
{
public ref T F;
public S(ref T t) { F = ref t; }
}
class Program
{
static void Main()
{
int x = 1;
int y = 2;
var sx = new S<int>(ref x);
var sy = new S<int>(ref y);
Reorder(sx, sy);
}
static ref S<T> Get<T>(ref S<T> s)
{
return ref s;
}
static void Reorder<T>(scoped S<T> sx, scoped S<T> sy)
{
M(y: in Get(ref sy).F, x: in Get(ref sx).F);
}
static void M<T>(in T x, in T y)
{
Console.WriteLine(x);
Console.WriteLine(y);
}
}";
var comp = CreateCompilation(new[] { source, UnscopedRefAttributeDefinition }, options: TestOptions.ReleaseExe, targetFramework: TargetFramework.Net70);
var verifier = CompileAndVerify(comp, verify: Verification.Skipped, expectedOutput: IncludeExpectedOutput(
@"1
2
"));
verifier.VerifyIL("Program.Reorder<T>",
@"{
// Code size 32 (0x20)
.maxstack 2
.locals init (T& V_0)
IL_0000: ldarga.s V_1
IL_0002: call ""ref S<T> Program.Get<T>(ref S<T>)""
IL_0007: ldfld ""ref T S<T>.F""
IL_000c: stloc.0
IL_000d: ldarga.s V_0
IL_000f: call ""ref S<T> Program.Get<T>(ref S<T>)""
IL_0014: ldfld ""ref T S<T>.F""
IL_0019: ldloc.0
IL_001a: call ""void Program.M<T>(in T, in T)""
IL_001f: ret
}");
}
[Theory]
[InlineData(LanguageVersion.CSharp10)]
[InlineData(LanguageVersion.CSharp11)]
public void ReturnRefToByValueParameter_01(LanguageVersion languageVersion)
{
var source =
@"
using System.Diagnostics.CodeAnalysis;
ref struct S<T>
{
}
class Program
{
static ref S<T> F1<T>([UnscopedRef] ref S<T> x1)
{
return ref x1;
}
static ref S<T> F2<T>(S<T> x2)
{
ref var y2 = ref F1(ref x2);
return ref y2; // 1
}
}";
var comp = CreateCompilation(new[] { source, UnscopedRefAttributeDefinition }, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion));
if (languageVersion == LanguageVersion.CSharp10)
{
comp.VerifyEmitDiagnostics(
// (8,28): error CS9063: UnscopedRefAttribute cannot be applied to this parameter because it is unscoped by default.
// static ref S<T> F1<T>([UnscopedRef] ref S<T> x1)
Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedTarget, "UnscopedRef").WithLocation(8, 28),
// (15,20): error CS8157: Cannot return 'y2' by reference because it was initialized to a value that cannot be returned by reference
// return ref y2; // 1
Diagnostic(ErrorCode.ERR_RefReturnNonreturnableLocal, "y2").WithArguments("y2").WithLocation(15, 20));
}
else
{
comp.VerifyEmitDiagnostics(
// (15,20): error CS8157: Cannot return 'y2' by reference because it was initialized to a value that cannot be returned by reference
// return ref y2; // 1
Diagnostic(ErrorCode.ERR_RefReturnNonreturnableLocal, "y2").WithArguments("y2").WithLocation(15, 20));
}
}
[Theory]
[InlineData(LanguageVersion.CSharp10)]
[InlineData(LanguageVersion.CSharp11)]
public void ReturnRefToByValueParameter_02(LanguageVersion languageVersion)
{
var source =
@"
ref struct S<T>
{
}
class Program
{
static ref S<T> F1<T>(ref S<T> x1, ref S<T> y1)
{
return ref x1;
}
static void F2<T>(S<T> x2, S<T> y2)
{
var z1 = F1(ref x2, ref y2);
}
}";
var comp = CreateCompilation(new[] { source, UnscopedRefAttributeDefinition }, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion));
comp.VerifyEmitDiagnostics();
}
[WorkItem(62098, "https://github.com/dotnet/roslyn/issues/62098")]
[Fact]
public void RefToContainingType()
{
var source =
@"
using System.Diagnostics.CodeAnalysis;
ref struct R<T>
{
public ref R<T> Next;
}
class Program
{
static void F<T>(ref R<T> r)
{
r.Next = ref r;
}
}";
var comp = CreateCompilation(new[] { source, UnscopedRefAttributeDefinition }, targetFramework: TargetFramework.Net70);
// https://github.com/dotnet/roslyn/issues/62098: Allow ref field of the containing type.
comp.VerifyEmitDiagnostics(
// (5,12): error CS9050: A ref field cannot refer to a ref struct.
// public ref R<T> Next;
Diagnostic(ErrorCode.ERR_RefFieldCannotReferToRefStruct, "ref R<T>").WithLocation(5, 12),
// (5,21): error CS0523: Struct member 'R<T>.Next' of type 'R<T>' causes a cycle in the struct layout
// public ref R<T> Next;
Diagnostic(ErrorCode.ERR_StructLayoutCycle, "Next").WithArguments("R<T>.Next", "R<T>").WithLocation(5, 21),
// (11,9): error CS9079: Cannot ref-assign 'r' to 'Next' because 'r' can only escape the current method through a return statement.
// r.Next = ref r;
Diagnostic(ErrorCode.ERR_RefAssignReturnOnly, "r.Next = ref r").WithArguments("Next", "r").WithLocation(11, 9));
}
/// <summary>
/// Ref auto-properties are not supported.
/// </summary>
[Fact]
public void RefAutoProperty_01()
{
var source =
@"using System;
ref struct S<T>
{
public ref T P0 { get; }
public ref T P1 { get; set; }
public ref T P2 { get; init; }
public S(ref T t)
{
P0 = ref t;
P1 = ref t;
P2 = ref t;
}
}
class Program
{
static void Main()
{
int x = 0;
var s = new S<int>(ref x);
s.P0 = 0;
s.P1 = 1;
s.P2 = 2;
s.P0 = ref x;
s.P1 = ref x;
s.P2 = ref x;
}
}";
var comp = CreateCompilation(source);
comp.VerifyEmitDiagnostics(
// (4,18): error CS8145: Auto-implemented properties cannot return by reference
// public ref T P0 { get; }
Diagnostic(ErrorCode.ERR_AutoPropertyCannotBeRefReturning, "P0").WithLocation(4, 18),
// (5,18): error CS8145: Auto-implemented properties cannot return by reference
// public ref T P1 { get; set; }
Diagnostic(ErrorCode.ERR_AutoPropertyCannotBeRefReturning, "P1").WithLocation(5, 18),
// (5,28): error CS8147: Properties which return by reference cannot have set accessors
// public ref T P1 { get; set; }
Diagnostic(ErrorCode.ERR_RefPropertyCannotHaveSetAccessor, "set").WithLocation(5, 28),
// (6,18): error CS8145: Auto-implemented properties cannot return by reference
// public ref T P2 { get; init; }
Diagnostic(ErrorCode.ERR_AutoPropertyCannotBeRefReturning, "P2").WithLocation(6, 18),
// (6,28): error CS0518: Predefined type 'System.Runtime.CompilerServices.IsExternalInit' is not defined or imported
// public ref T P2 { get; init; }
Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound, "init").WithArguments("System.Runtime.CompilerServices.IsExternalInit").WithLocation(6, 28),
// (6,28): error CS8147: Properties which return by reference cannot have set accessors
// public ref T P2 { get; init; }
Diagnostic(ErrorCode.ERR_RefPropertyCannotHaveSetAccessor, "init").WithLocation(6, 28),
// (9,9): error CS8373: The left-hand side of a ref assignment must be a ref variable.
// P0 = ref t;
Diagnostic(ErrorCode.ERR_RefLocalOrParamExpected, "P0").WithLocation(9, 9),
// (10,9): error CS8373: The left-hand side of a ref assignment must be a ref variable.
// P1 = ref t;
Diagnostic(ErrorCode.ERR_RefLocalOrParamExpected, "P1").WithLocation(10, 9),
// (11,9): error CS8373: The left-hand side of a ref assignment must be a ref variable.
// P2 = ref t;
Diagnostic(ErrorCode.ERR_RefLocalOrParamExpected, "P2").WithLocation(11, 9),
// (23,9): error CS8373: The left-hand side of a ref assignment must be a ref variable.
// s.P0 = ref x;
Diagnostic(ErrorCode.ERR_RefLocalOrParamExpected, "s.P0").WithLocation(23, 9),
// (24,9): error CS8373: The left-hand side of a ref assignment must be a ref variable.
// s.P1 = ref x;
Diagnostic(ErrorCode.ERR_RefLocalOrParamExpected, "s.P1").WithLocation(24, 9),
// (25,9): error CS8373: The left-hand side of a ref assignment must be a ref variable.
// s.P2 = ref x;
Diagnostic(ErrorCode.ERR_RefLocalOrParamExpected, "s.P2").WithLocation(25, 9));
}
/// <summary>
/// Ref auto-properties are not supported.
/// </summary>
[Fact]
public void RefAutoProperty_02()
{
var source =
@"using System;
ref struct S<T>
{
public ref readonly T P0 { get; }
public ref readonly T P1 { get; set; }
public ref readonly T P2 { get; init; }
public S(ref T t)
{
P0 = ref t;
P1 = ref t;
P2 = ref t;
}
}
class Program
{
static void Main()
{
int x = 0;
var s = new S<int>(ref x);
s.P0 = ref x;
s.P1 = ref x;
s.P2 = ref x;
}
}";
var comp = CreateCompilation(source);
comp.VerifyEmitDiagnostics(
// (4,27): error CS8145: Auto-implemented properties cannot return by reference
// public ref readonly T P0 { get; }
Diagnostic(ErrorCode.ERR_AutoPropertyCannotBeRefReturning, "P0").WithLocation(4, 27),
// (5,27): error CS8145: Auto-implemented properties cannot return by reference
// public ref readonly T P1 { get; set; }
Diagnostic(ErrorCode.ERR_AutoPropertyCannotBeRefReturning, "P1").WithLocation(5, 27),
// (5,37): error CS8147: Properties which return by reference cannot have set accessors
// public ref readonly T P1 { get; set; }
Diagnostic(ErrorCode.ERR_RefPropertyCannotHaveSetAccessor, "set").WithLocation(5, 37),
// (6,27): error CS8145: Auto-implemented properties cannot return by reference
// public ref readonly T P2 { get; init; }
Diagnostic(ErrorCode.ERR_AutoPropertyCannotBeRefReturning, "P2").WithLocation(6, 27),
// (6,37): error CS0518: Predefined type 'System.Runtime.CompilerServices.IsExternalInit' is not defined or imported
// public ref readonly T P2 { get; init; }
Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound, "init").WithArguments("System.Runtime.CompilerServices.IsExternalInit").WithLocation(6, 37),
// (6,37): error CS8147: Properties which return by reference cannot have set accessors
// public ref readonly T P2 { get; init; }
Diagnostic(ErrorCode.ERR_RefPropertyCannotHaveSetAccessor, "init").WithLocation(6, 37),
// (9,9): error CS8373: The left-hand side of a ref assignment must be a ref variable.
// P0 = ref t;
Diagnostic(ErrorCode.ERR_RefLocalOrParamExpected, "P0").WithLocation(9, 9),
// (10,9): error CS8373: The left-hand side of a ref assignment must be a ref variable.
// P1 = ref t;
Diagnostic(ErrorCode.ERR_RefLocalOrParamExpected, "P1").WithLocation(10, 9),
// (11,9): error CS8373: The left-hand side of a ref assignment must be a ref variable.
// P2 = ref t;
Diagnostic(ErrorCode.ERR_RefLocalOrParamExpected, "P2").WithLocation(11, 9),
// (20,9): error CS8373: The left-hand side of a ref assignment must be a ref variable.
// s.P0 = ref x;
Diagnostic(ErrorCode.ERR_RefLocalOrParamExpected, "s.P0").WithLocation(20, 9),
// (21,9): error CS8373: The left-hand side of a ref assignment must be a ref variable.
// s.P1 = ref x;
Diagnostic(ErrorCode.ERR_RefLocalOrParamExpected, "s.P1").WithLocation(21, 9),
// (22,9): error CS8373: The left-hand side of a ref assignment must be a ref variable.
// s.P2 = ref x;
Diagnostic(ErrorCode.ERR_RefLocalOrParamExpected, "s.P2").WithLocation(22, 9));
}
[Fact]
[WorkItem(60807, "https://github.com/dotnet/roslyn/issues/60807")]
public void RefAndOut_PropertiesAndIndexers_As_ValuesAndParameters()
{
var source =
@"
var c = new C();
var r = new R();
//expressions
ref int n = ref c.N; //CS0206
ref var l = ref c[0]; //CS0206
ref var l2 = ref r[0];//OK
_ = M(ref c.N); //CS0206
_ = M(ref r.N); //OK
_ = M(ref c[0]); //CS0206
_ = M(ref r[0]); //OK
_ = M2(out c.N); //CS0206
_ = M2(out r.N); //OK
_ = M2(out c[0]); //CS0206
_ = M2(out r[0]); //OK
//definitions
static string M(ref int number) { return """"; }
static string M2(out int number) { number = 42; return """"; }
class C
{
public int N { get; set; }
private int[] arr = new int[100];
public int this[int i] => arr[i];
}
ref struct R
{
public R(){}
private ref int n;
public ref int N => ref n;
private static int[] s_arr = new int[1];
private ref int[] arr = ref s_arr;
public ref int this[int i] => ref arr[i];
}
";
var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70);
comp.VerifyEmitDiagnostics(
// (5,17): error CS0206: A non ref-returning property or indexer may not be used as an out or ref value
// ref int n = ref c.N; //CS0206
Diagnostic(ErrorCode.ERR_RefProperty, "c.N").WithLocation(5, 17),
// (6,17): error CS0206: A non ref-returning property or indexer may not be used as an out or ref value
// ref var l = ref c[0]; //CS0206
Diagnostic(ErrorCode.ERR_RefProperty, "c[0]").WithLocation(6, 17),
// (8,11): error CS0206: A non ref-returning property or indexer may not be used as an out or ref value
// _ = M(ref c.N); //CS0206
Diagnostic(ErrorCode.ERR_RefProperty, "c.N").WithLocation(8, 11),
// (10,11): error CS0206: A non ref-returning property or indexer may not be used as an out or ref value
// _ = M(ref c[0]); //CS0206
Diagnostic(ErrorCode.ERR_RefProperty, "c[0]").WithLocation(10, 11),
// (12,12): error CS0206: A non ref-returning property or indexer may not be used as an out or ref value
// _ = M2(out c.N); //CS0206
Diagnostic(ErrorCode.ERR_RefProperty, "c.N").WithLocation(12, 12),
// (14,12): error CS0206: A non ref-returning property or indexer may not be used as an out or ref value
// _ = M2(out c[0]); //CS0206
Diagnostic(ErrorCode.ERR_RefProperty, "c[0]").WithLocation(14, 12)
);
}
[Fact]
public void RefAccessor_Value()
{
var source =
@"using System;
ref struct S<T>
{
internal T t;
internal ref T F() => ref t;
}
class Program
{
static void Main()
{
var s = new S<int>();
s.t = 1;
s.F() = 2;
Console.WriteLine(s.F());
Console.WriteLine(s.t);
s.t = 3;
Console.WriteLine(s.F());
Console.WriteLine(s.t);
}
}";
var comp = CreateCompilation(source);
comp.VerifyEmitDiagnostics(
// (5,31): error CS8170: Struct members cannot return 'this' or other instance members by reference
// internal ref T F() => ref t;
Diagnostic(ErrorCode.ERR_RefReturnStructThis, "t").WithLocation(5, 31));
}
[Fact]
public void RefAccessor_Ref()
{
var source =
@"using System;
ref struct S<T>
{
internal ref T t;
internal ref T F() => ref t;
internal S(ref T t) { this.t = ref t; }
}
class Program
{
static void Main()
{
int i = 0;
var s = new S<int>(ref i);
s.t = 1;
s.F() = 2;
Console.WriteLine(s.F());
Console.WriteLine(s.t);
s.t = 3;
Console.WriteLine(s.F());
Console.WriteLine(s.t);
}
}";
var comp = CreateCompilation(source, options: TestOptions.ReleaseExe, targetFramework: TargetFramework.Net70);
var verifier = CompileAndVerify(comp, verify: Verification.Skipped, expectedOutput: IncludeExpectedOutput(
@"2
2
3
3
"));
verifier.VerifyIL("S<T>.F",
@"{
// Code size 7 (0x7)
.maxstack 1
IL_0000: ldarg.0
IL_0001: ldfld ""ref T S<T>.t""
IL_0006: ret
}");
}
[Theory]
[InlineData(LanguageVersion.CSharp10)]
[InlineData(LanguageVersion.CSharp11)]
public void Span_01(LanguageVersion languageVersion)
{
var source =
@"using System;
class Program
{
static ref int F1()
{
Span<int> s1 = stackalloc int[10];
return ref s1[1]; // 1
}
static ref int F2()
{
Span<int> s2 = new int[10];
return ref s2[1];
}
}";
var comp = CreateCompilationWithSpanAndMemoryExtensions(source, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion));
comp.VerifyEmitDiagnostics(
// (7,20): error CS8352: Cannot use variable 's1' in this context because it may expose referenced variables outside of their declaration scope
// return ref s1[1]; // 1
Diagnostic(ErrorCode.ERR_EscapeVariable, "s1").WithArguments("s1").WithLocation(7, 20));
}
// A version of above with an explicit definition of Span<T>.
[Theory]
[InlineData(LanguageVersion.CSharp10)]
[InlineData(LanguageVersion.CSharp11)]
public void Span_02(LanguageVersion languageVersion)
{
var sourceA =
@"namespace System
{
public ref struct Span<T>
{
unsafe public Span(void* ptr, int length) { }
public ref T this[int index] => throw null;
public static implicit operator Span<T>(T[] a) => throw null;
}
}";
var comp = CreateCompilation(sourceA, parseOptions: TestOptions.Regular10, options: TestOptions.UnsafeReleaseDll);
var refA = comp.EmitToImageReference();
var sourceB =
@"using System;
class Program
{
static ref int F1()
{
Span<int> s1 = stackalloc int[10];
return ref s1[1]; // 1
}
static ref int F2()
{
Span<int> s2 = new int[10];
return ref s2[1];
}
}";
comp = CreateCompilation(sourceB, references: new[] { refA }, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion));
comp.VerifyEmitDiagnostics(
// (7,20): error CS8352: Cannot use variable 's1' in this context because it may expose referenced variables outside of their declaration scope
// return ref s1[1]; // 1
Diagnostic(ErrorCode.ERR_EscapeVariable, "s1").WithArguments("s1").WithLocation(7, 20));
}
[Fact, WorkItem(63104, "https://github.com/dotnet/roslyn/issues/63104")]
public void RefFieldsConsideredManaged()
{
var source = @"
unsafe
{
StructWithRefField* p = stackalloc StructWithRefField[10]; // 1, 2
C.M<StructWithRefField>(); // 3
}
public ref struct StructWithRefField
{
public ref byte RefField;
}
class C
{
public static void M<T>() where T : unmanaged { }
}";
var comp = CreateCompilation(source, options: TestOptions.UnsafeDebugExe, targetFramework: TargetFramework.Net70);
comp.VerifyDiagnostics(
// (4,5): warning CS8500: This takes the address of, gets the size of, or declares a pointer to a managed type ('StructWithRefField')
// StructWithRefField* p = stackalloc StructWithRefField[10]; // 1, 2
Diagnostic(ErrorCode.WRN_ManagedAddr, "StructWithRefField*").WithArguments("StructWithRefField").WithLocation(4, 5),
// (4,40): error CS0208: Cannot take the address of, get the size of, or declare a pointer to a managed type ('StructWithRefField')
// StructWithRefField* p = stackalloc StructWithRefField[10]; // 1, 2
Diagnostic(ErrorCode.ERR_ManagedAddr, "StructWithRefField").WithArguments("StructWithRefField").WithLocation(4, 40),
// (5,7): error CS0306: The type 'StructWithRefField' may not be used as a type argument
// C.M<StructWithRefField>(); // 3
Diagnostic(ErrorCode.ERR_BadTypeArgument, "M<StructWithRefField>").WithArguments("StructWithRefField").WithLocation(5, 7)
);
Assert.True(comp.GetTypeByMetadataName("StructWithRefField").IsManagedTypeNoUseSiteDiagnostics);
}
[Fact, WorkItem(63104, "https://github.com/dotnet/roslyn/issues/63104")]
public void RefFieldsConsideredManaged_Generic()
{
var source = @"
unsafe
{
StructWithIndirectRefField* p = stackalloc StructWithIndirectRefField[10]; // 1, 2
C.M<StructWithIndirectRefField>(); // 3
}
ref struct StructWithIndirectRefField
{
public StructWithRefField<int> Field;
}
ref struct StructWithRefField<T>
{
public ref T RefField;
}
class C
{
public static void M<T>() where T : unmanaged { }
}";
var comp = CreateCompilation(source, options: TestOptions.UnsafeDebugExe, targetFramework: TargetFramework.Net70);
comp.VerifyDiagnostics(
// (4,5): warning CS8500: This takes the address of, gets the size of, or declares a pointer to a managed type ('StructWithIndirectRefField')
// StructWithIndirectRefField* p = stackalloc StructWithIndirectRefField[10]; // 1, 2
Diagnostic(ErrorCode.WRN_ManagedAddr, "StructWithIndirectRefField*").WithArguments("StructWithIndirectRefField").WithLocation(4, 5),
// (4,48): error CS0208: Cannot take the address of, get the size of, or declare a pointer to a managed type ('StructWithIndirectRefField')
// StructWithIndirectRefField* p = stackalloc StructWithIndirectRefField[10]; // 1, 2
Diagnostic(ErrorCode.ERR_ManagedAddr, "StructWithIndirectRefField").WithArguments("StructWithIndirectRefField").WithLocation(4, 48),
// (5,7): error CS0306: The type 'StructWithIndirectRefField' may not be used as a type argument
// C.M<StructWithIndirectRefField>(); // 3
Diagnostic(ErrorCode.ERR_BadTypeArgument, "M<StructWithIndirectRefField>").WithArguments("StructWithIndirectRefField").WithLocation(5, 7),
// (10,36): warning CS0649: Field 'StructWithIndirectRefField.Field' is never assigned to, and will always have its default value
// public StructWithRefField<int> Field;
Diagnostic(ErrorCode.WRN_UnassignedInternalField, "Field").WithArguments("StructWithIndirectRefField.Field", "").WithLocation(10, 36),
// (14,18): warning CS0649: Field 'StructWithRefField<T>.RefField' is never assigned to, and will always have its default value
// public ref T RefField;
Diagnostic(ErrorCode.WRN_UnassignedInternalField, "RefField").WithArguments("StructWithRefField<T>.RefField", "").WithLocation(14, 18)
);
Assert.True(comp.GetTypeByMetadataName("StructWithIndirectRefField").IsManagedTypeNoUseSiteDiagnostics);
}
[Fact, WorkItem(63104, "https://github.com/dotnet/roslyn/issues/63104")]
public void RefFieldsConsideredManaged_Indirect()
{
var source = @"
unsafe
{
StructWithIndirectRefField* p = stackalloc StructWithIndirectRefField[10]; // 1, 2
}
public ref struct StructWithIndirectRefField
{
public StructWithRefField Field;
}
public ref struct StructWithRefField
{
public ref byte RefField;
}";
var comp = CreateCompilation(source, options: TestOptions.UnsafeDebugExe, targetFramework: TargetFramework.Net70);
comp.VerifyDiagnostics(
// (4,5): warning CS8500: This takes the address of, gets the size of, or declares a pointer to a managed type ('StructWithIndirectRefField')
// StructWithIndirectRefField* p = stackalloc StructWithIndirectRefField[10]; // 1, 2
Diagnostic(ErrorCode.WRN_ManagedAddr, "StructWithIndirectRefField*").WithArguments("StructWithIndirectRefField").WithLocation(4, 5),
// (4,48): error CS0208: Cannot take the address of, get the size of, or declare a pointer to a managed type ('StructWithIndirectRefField')
// StructWithIndirectRefField* p = stackalloc StructWithIndirectRefField[10]; // 1, 2
Diagnostic(ErrorCode.ERR_ManagedAddr, "StructWithIndirectRefField").WithArguments("StructWithIndirectRefField").WithLocation(4, 48)
);
Assert.True(comp.GetTypeByMetadataName("StructWithIndirectRefField").IsManagedTypeNoUseSiteDiagnostics);
}
[WorkItem(62618, "https://github.com/dotnet/roslyn/issues/62618")]
[Theory]
[CombinatorialData]
public void RefAssignValueScopeMismatch_01A(
[CombinatorialValues(LanguageVersion.CSharp10, LanguageVersion.CSharp11)] LanguageVersion languageVersion,
bool useUnsafe)
{
string unsafeModifier = useUnsafe ? "unsafe" : "";
var source =
$@"using System;
class Program
{{
static void Main()
{{
Span<int> s = new[] {{ 1 }};
M(ref s);
}}
{unsafeModifier} static void M(ref Span<int> s)
{{
Span<int> local = stackalloc int[] {{ 1 }};
ref Span<int> rL = ref local;
rL = ref s; // 1
rL = local;
}}
}}";
var comp = CreateCompilationWithSpanAndMemoryExtensions(source,
parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion),
options: (useUnsafe ? TestOptions.UnsafeReleaseExe : null));
if (useUnsafe)
{
comp.VerifyEmitDiagnostics(
// (13,9): warning CS9097: This ref-assigns 's' to 'rL' but 's' has a wider value escape scope than 'rL' allowing assignment through 'rL' of values with narrower escapes scopes than 's'.
// rL = ref s; // 1
Diagnostic(ErrorCode.WRN_RefAssignValEscapeWider, "rL = ref s").WithArguments("rL", "s").WithLocation(13, 9));
}
else
{
comp.VerifyEmitDiagnostics(
// (13,9): error CS9096: Cannot ref-assign 's' to 'rL' because 's' has a wider value escape scope than 'rL' allowing assignment through 'rL' of values with narrower escapes scopes than 's'.
// rL = ref s; // 1
Diagnostic(ErrorCode.ERR_RefAssignValEscapeWider, "rL = ref s").WithArguments("rL", "s").WithLocation(13, 9));
}
}
[WorkItem(62618, "https://github.com/dotnet/roslyn/issues/62618")]
[Theory]
[CombinatorialData]
public void RefAssignValueScopeMismatch_01B(
[CombinatorialValues(LanguageVersion.CSharp10, LanguageVersion.CSharp11)] LanguageVersion languageVersion,
bool useUnsafe)
{
string unsafeModifier = useUnsafe ? "unsafe" : "";
var source =
$@"using System;
class Program
{{
static void Main()
{{
Span<int> s = new[] {{ 1 }};
M(ref s);
}}
{unsafeModifier} static void M(ref Span<int> s)
{{
Span<int> local = stackalloc int[] {{ 1 }};
ref readonly Span<int> rL = ref local;
rL = ref s; // 1
rL = local; // 2
}}
}}";
var comp = CreateCompilationWithSpanAndMemoryExtensions(source,
parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion),
options: (useUnsafe ? TestOptions.UnsafeReleaseExe : null));
if (useUnsafe)
{
comp.VerifyEmitDiagnostics(
// (13,9): warning CS9097: This ref-assigns 's' to 'rL' but 's' has a wider value escape scope than 'rL' allowing assignment through 'rL' of values with narrower escapes scopes than 's'.
// rL = ref s; // 1
Diagnostic(ErrorCode.WRN_RefAssignValEscapeWider, "rL = ref s").WithArguments("rL", "s").WithLocation(13, 9),
// (14,9): error CS0131: The left-hand side of an assignment must be a variable, property or indexer
// rL = local; // 2
Diagnostic(ErrorCode.ERR_AssgLvalueExpected, "rL").WithLocation(14, 9));
}
else
{
comp.VerifyEmitDiagnostics(
// (13,9): error CS9096: Cannot ref-assign 's' to 'rL' because 's' has a wider value escape scope than 'rL' allowing assignment through 'rL' of values with narrower escapes scopes than 's'.
// rL = ref s; // 1
Diagnostic(ErrorCode.ERR_RefAssignValEscapeWider, "rL = ref s").WithArguments("rL", "s").WithLocation(13, 9),
// (14,9): error CS0131: The left-hand side of an assignment must be a variable, property or indexer
// rL = local; // 2
Diagnostic(ErrorCode.ERR_AssgLvalueExpected, "rL").WithLocation(14, 9));
}
}
[WorkItem(62618, "https://github.com/dotnet/roslyn/issues/62618")]
[Theory]
[CombinatorialData]
public void RefAssignValueScopeMismatch_02(
[CombinatorialValues(LanguageVersion.CSharp10, LanguageVersion.CSharp11)] LanguageVersion languageVersion,
bool useUnsafe)
{
string unsafeModifier = useUnsafe ? "unsafe" : "";
var source =
$@"ref struct R
{{
public R(ref int i) {{ }}
}}
class Program
{{
static void Main()
{{
R r = default;
M(ref r);
}}
{unsafeModifier} static void M(ref R r1)
{{
int i = 0;
R local = new R(ref i);
ref R r2 = ref local;
r2 = ref r1; // 1
r2 = local;
}}
}}";
var comp = CreateCompilation(source,
parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion),
options: (useUnsafe ? TestOptions.UnsafeReleaseExe : null));
if (languageVersion == LanguageVersion.CSharp10)
{
comp.VerifyEmitDiagnostics();
}
else if (useUnsafe)
{
comp.VerifyEmitDiagnostics(
// (17,9): warning CS9097: This ref-assigns 'r1' to 'r2' but 'r1' has a wider value escape scope than 'r2' allowing assignment through 'r2' of values with narrower escapes scopes than 'r1'.
// r2 = ref r1; // 1
Diagnostic(ErrorCode.WRN_RefAssignValEscapeWider, "r2 = ref r1").WithArguments("r2", "r1").WithLocation(17, 9));
}
else
{
comp.VerifyEmitDiagnostics(
// (17,9): error CS9096: Cannot ref-assign 'r1' to 'r2' because 'r1' has a wider value escape scope than 'r2' allowing assignment through 'r2' of values with narrower escapes scopes than 'r1'.
// r2 = ref r1; // 1
Diagnostic(ErrorCode.ERR_RefAssignValEscapeWider, "r2 = ref r1").WithArguments("r2", "r1").WithLocation(17, 9));
}
}
[WorkItem(62618, "https://github.com/dotnet/roslyn/issues/62618")]
[Theory]
[InlineData(LanguageVersion.CSharp10)]
[InlineData(LanguageVersion.CSharp11)]
public void RefAssignValueScopeMismatch_03(LanguageVersion languageVersion)
{
var source =
@"ref struct R1
{
public R2 F;
}
ref struct R2
{
public R2(ref int i) { }
}
class Program
{
static void Main()
{
R1 r = default;
M(ref r);
}
static void M(ref R1 r1)
{
int i = 0;
R2 local = new R2(ref i);
ref R2 r2 = ref local;
r2 = ref r1.F; // 1
r2 = local;
}
}";
var comp = CreateCompilation(source, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion));
if (languageVersion == LanguageVersion.CSharp10)
{
comp.VerifyEmitDiagnostics();
}
else
{
comp.VerifyEmitDiagnostics(
// (21,9): error CS9096: Cannot ref-assign 'r1.F' to 'r2' because 'r1.F' has a wider value escape scope than 'r2' allowing assignment through 'r2' of values with narrower escapes scopes than 'r1.F'.
// r2 = ref r1.F; // 1
Diagnostic(ErrorCode.ERR_RefAssignValEscapeWider, "r2 = ref r1.F").WithArguments("r2", "r1.F").WithLocation(21, 9));
}
}
[WorkItem(62618, "https://github.com/dotnet/roslyn/issues/62618")]
[Fact]
public void RefAssignValueScopeMismatch_04()
{
var source =
@"using System;
class Program
{
static Span<int> F()
{
Span<int> s1 = default;
{
scoped ref Span<int> r1 = ref s1;
Span<int> s2 = stackalloc int[1];
ref Span<int> r2 = ref s2;
r2 = ref r1; // 1
r2 = s2;
}
return s1;
}
}";
var comp = CreateCompilationWithSpanAndMemoryExtensions(source);
comp.VerifyEmitDiagnostics(
// (11,13): error CS9096: Cannot ref-assign 'r1' to 'r2' because 'r1' has a wider value escape scope than 'r2' allowing assignment through 'r2' of values with narrower escapes scopes than 'r1'.
// r2 = ref r1; // 1
Diagnostic(ErrorCode.ERR_RefAssignValEscapeWider, "r2 = ref r1").WithArguments("r2", "r1").WithLocation(11, 13));
}
[WorkItem(62618, "https://github.com/dotnet/roslyn/issues/62618")]
[Fact]
public void RefAssignValueScopeMismatch_05()
{
var source =
@"ref struct S
{
public S(ref int i) { }
}
class Program
{
static S F()
{
S s1 = default;
scoped ref S r1 = ref s1;
int i = 0;
S s2 = new S(ref i);
ref S r2 = ref s2;
r2 = ref r1; // 1
r2 = s2;
return s1;
}
}";
var comp = CreateCompilation(source);
comp.VerifyEmitDiagnostics(
// (14,9): error CS9096: Cannot ref-assign 'r1' to 'r2' because 'r1' has a wider value escape scope than 'r2' allowing assignment through 'r2' of values with narrower escapes scopes than 'r1'.
// r2 = ref r1; // 1
Diagnostic(ErrorCode.ERR_RefAssignValEscapeWider, "r2 = ref r1").WithArguments("r2", "r1").WithLocation(14, 9));
}
[Theory]
[CombinatorialData]
public void RefAssignValueScopeMismatch_06(bool useUnsafe)
{
string unsafeModifier = useUnsafe ? "unsafe" : "";
var source =
$@"ref struct S
{{
public S(ref int i) {{ }}
}}
class Program
{{
{unsafeModifier} static S F()
{{
S s1 = default;
scoped ref S r1 = ref s1;
scoped S s2 = default;
ref S r2 = ref s2;
r1 = ref r2; // 1
r2 = s2;
return s1;
}}
}}";
var comp = CreateCompilation(source,
options: (useUnsafe ? TestOptions.UnsafeReleaseDll : null));
if (useUnsafe)
{
comp.VerifyEmitDiagnostics(
// (13,18): warning CS9080: Use of variable 'r2' in this context may expose referenced variables outside of their declaration scope
// r1 = ref r2; // 1
Diagnostic(ErrorCode.WRN_EscapeVariable, "r2").WithArguments("r2").WithLocation(13, 18));
}
else
{
comp.VerifyEmitDiagnostics(
// (13,18): error CS8352: Cannot use variable 'r2' in this context because it may expose referenced variables outside of their declaration scope
// r1 = ref r2;
Diagnostic(ErrorCode.ERR_EscapeVariable, "r2").WithArguments("r2").WithLocation(13, 18));
}
}
// Breaking change in C#11: Cannot return an 'out' parameter by reference.
[Fact]
public void BreakingChange_ReturnOutByRef()
{
var source =
@"class Program
{
static ref T ReturnOutParamByRef<T>(out T t)
{
t = default;
return ref t;
}
}";
var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10);
comp.VerifyDiagnostics();
comp = CreateCompilation(source);
comp.VerifyDiagnostics(
// (6,20): error CS9075: Cannot return a parameter by reference 't' because it is scoped to the current method
// return ref t;
Diagnostic(ErrorCode.ERR_RefReturnScopedParameter, "t").WithArguments("t").WithLocation(6, 20));
}
[Theory]
[CombinatorialData]
public void InstanceMethodCannotCaptureRefByRef(
[CombinatorialValues(LanguageVersion.CSharp10, LanguageVersion.CSharp11)] LanguageVersion languageVersionA,
[CombinatorialValues(LanguageVersion.CSharp10, LanguageVersion.CSharp11)] LanguageVersion languageVersionB,
bool useCompilationReference)
{
var sourceA =
@"public ref struct R<T>
{
public void MayCaptureArg(ref T t) { }
}";
var comp = CreateCompilation(sourceA, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersionA));
comp.VerifyEmitDiagnostics();
var refA = AsReference(comp, useCompilationReference);
var sourceB =
@"class Program
{
static R<int> Use(R<int> r)
{
int i = 42;
r.MayCaptureArg(ref i);
return r;
}
}";
comp = CreateCompilation(sourceB, references: new[] { refA }, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersionB));
comp.VerifyEmitDiagnostics();
}
[Theory]
[CombinatorialData]
public void RefStructInstanceMethodMayCaptureRef(
[CombinatorialValues(LanguageVersion.CSharp10, LanguageVersion.CSharp11)] LanguageVersion languageVersionA,
[CombinatorialValues(LanguageVersion.CSharp10, LanguageVersion.CSharp11)] LanguageVersion languageVersionB,
bool useCompilationReference)
{
var sourceA =
@"public ref struct R<T>
{
public void MayCaptureArg(ref T t) { }
public static R<int> Create(ref int i) => default;
}";
var comp = CreateCompilation(sourceA, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersionA));
comp.VerifyEmitDiagnostics();
var refA = AsReference(comp, useCompilationReference);
var sourceB =
@"class Program
{
static void Use()
{
int x = 1;
int y = 2;
R<int>.Create(ref x).MayCaptureArg(ref y);
}
}";
comp = CreateCompilation(sourceB, references: new[] { refA }, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersionB));
comp.VerifyEmitDiagnostics();
}
// Breaking change in C#11: The rvalue from a method invocation that
// returns a ref struct is safe-to-escape from ... the ref-safe-to-escape of all ref arguments.
[Theory]
[CombinatorialData]
public void BreakingChange_RefStructReturnFromRefArguments_01(
[CombinatorialValues(LanguageVersion.CSharp10, LanguageVersion.CSharp11)] LanguageVersion languageVersionA,
[CombinatorialValues(LanguageVersion.CSharp10, LanguageVersion.CSharp11)] LanguageVersion languageVersionB,
bool useCompilationReference)
{
var sourceA =
@"public ref struct R { }
public class A
{
public static R MayCaptureArg(ref int i) => new R();
public static R MayCaptureDefaultArg(in int i = 0) => new R();
}";
var comp = CreateCompilation(sourceA, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersionA));
comp.VerifyEmitDiagnostics();
var refA = AsReference(comp, useCompilationReference);
var sourceB =
@"class B : A
{
static R Create()
{
int i = 0;
return MayCaptureArg(ref i);
}
static R CreateDefault()
{
return MayCaptureDefaultArg();
}
}";
comp = CreateCompilation(sourceB, references: new[] { refA }, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersionB));
if (languageVersionA == LanguageVersion.CSharp10)
{
comp.VerifyEmitDiagnostics();
}
else
{
comp.VerifyEmitDiagnostics(
// (6,16): error CS8347: Cannot use a result of 'A.MayCaptureArg(ref int)' in this context because it may expose variables referenced by parameter 'i' outside of their declaration scope
// return MayCaptureArg(ref i);
Diagnostic(ErrorCode.ERR_EscapeCall, "MayCaptureArg(ref i)").WithArguments("A.MayCaptureArg(ref int)", "i").WithLocation(6, 16),
// (6,34): error CS8168: Cannot return local 'i' by reference because it is not a ref local
// return MayCaptureArg(ref i);
Diagnostic(ErrorCode.ERR_RefReturnLocal, "i").WithArguments("i").WithLocation(6, 34),
// (10,16): error CS8156: An expression cannot be used in this context because it may not be passed or returned by reference
// return MayCaptureDefaultArg();
Diagnostic(ErrorCode.ERR_RefReturnLvalueExpected, "MayCaptureDefaultArg()").WithLocation(10, 16),
// (10,16): error CS8347: Cannot use a result of 'A.MayCaptureDefaultArg(in int)' in this context because it may expose variables referenced by parameter 'i' outside of their declaration scope
// return MayCaptureDefaultArg();
Diagnostic(ErrorCode.ERR_EscapeCall, "MayCaptureDefaultArg()").WithArguments("A.MayCaptureDefaultArg(in int)", "i").WithLocation(10, 16));
}
}
// Another version of the breaking change above, this time
// with ref structs passed by reference as constructor this.
[WorkItem(62940, "https://github.com/dotnet/roslyn/issues/62940")]
[Theory]
[CombinatorialData]
public void BreakingChange_RefStructReturnFromRefArguments_02(
[CombinatorialValues(LanguageVersion.CSharp10, LanguageVersion.CSharp11)] LanguageVersion languageVersionA,
[CombinatorialValues(LanguageVersion.CSharp10, LanguageVersion.CSharp11)] LanguageVersion languageVersionB,
bool useCompilationReference)
{
var sourceA =
@"public ref struct R1
{
public R1(ref object o) { }
}
public readonly ref struct R2
{
public R2(in object o) { }
}";
var comp = CreateCompilation(sourceA, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersionA));
comp.VerifyEmitDiagnostics();
var refA = AsReference(comp, useCompilationReference);
var sourceB =
@"class Program
{
static R1 F1()
{
var o = new object();
return new R1(ref o);
}
static R2 F2()
{
return new R2(new object());
}
}";
comp = CreateCompilation(sourceB, references: new[] { refA }, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersionB));
if (languageVersionA == LanguageVersion.CSharp10)
{
comp.VerifyEmitDiagnostics();
}
else
{
comp.VerifyEmitDiagnostics(
// (6,16): error CS8347: Cannot use a result of 'R1.R1(ref object)' in this context because it may expose variables referenced by parameter 'o' outside of their declaration scope
// return new R1(ref o);
Diagnostic(ErrorCode.ERR_EscapeCall, "new R1(ref o)").WithArguments("R1.R1(ref object)", "o").WithLocation(6, 16),
// (6,27): error CS8168: Cannot return local 'o' by reference because it is not a ref local
// return new R1(ref o);
Diagnostic(ErrorCode.ERR_RefReturnLocal, "o").WithArguments("o").WithLocation(6, 27),
// (10,16): error CS8347: Cannot use a result of 'R2.R2(in object)' in this context because it may expose variables referenced by parameter 'o' outside of their declaration scope
// return new R2(new object());
Diagnostic(ErrorCode.ERR_EscapeCall, "new R2(new object())").WithArguments("R2.R2(in object)", "o").WithLocation(10, 16),
// (10,23): error CS8156: An expression cannot be used in this context because it may not be passed or returned by reference
// return new R2(new object());
Diagnostic(ErrorCode.ERR_RefReturnLvalueExpected, "new object()").WithLocation(10, 23));
}
}
// Another version of the breaking change above, this time
// with a function pointer type.
[Theory]
[CombinatorialData]
public void BreakingChange_RefStructReturnFromRefArguments_03(
[CombinatorialValues(LanguageVersion.CSharp10, LanguageVersion.CSharp11)] LanguageVersion languageVersionA,
[CombinatorialValues(LanguageVersion.CSharp10, LanguageVersion.CSharp11)] LanguageVersion languageVersionB,
bool useCompilationReference)
{
var sourceA =
@"public ref struct R { }
unsafe public class A
{
private static R _MayCaptureArg(ref int i) => new R();
public static delegate*<ref int, R> MayCaptureArg = &_MayCaptureArg;
}";
var comp = CreateCompilation(sourceA, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersionA), options: TestOptions.UnsafeReleaseDll);
comp.VerifyEmitDiagnostics();
var refA = AsReference(comp, useCompilationReference);
var sourceB =
@"class B : A
{
unsafe static R Create()
{
int i = 0;
return MayCaptureArg(ref i);
}
}";
comp = CreateCompilation(sourceB, references: new[] { refA }, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersionB), options: TestOptions.UnsafeReleaseDll);
if (languageVersionA == LanguageVersion.CSharp10)
{
comp.VerifyEmitDiagnostics();
}
else
{
comp.VerifyEmitDiagnostics(
// (6,34): warning CS9091: This returns local 'i' by reference but it is not a ref local
// return MayCaptureArg(ref i);
Diagnostic(ErrorCode.WRN_RefReturnLocal, "i").WithArguments("i").WithLocation(6, 34));
}
}
// Breaking change in C#11: A ref to ref struct argument is considered
// an unscoped reference when passed to an __arglist.
[Theory]
[CombinatorialData]
public void BreakingChange_RefToRefStructInArglist(
[CombinatorialValues(LanguageVersion.CSharp10, LanguageVersion.CSharp11)] LanguageVersion languageVersionA,
[CombinatorialValues(LanguageVersion.CSharp10, LanguageVersion.CSharp11)] LanguageVersion languageVersionB,
bool useCompilationReference)
{
var sourceA =
@"public ref struct R { }
public class A
{
public static void MayCaptureRef(__arglist) { }
}";
var comp = CreateCompilation(sourceA, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersionA));
comp.VerifyEmitDiagnostics();
var refA = AsReference(comp, useCompilationReference);
var sourceB =
@"class B : A
{
static void Main()
{
var r = new R();
MayCaptureRef(__arglist(ref r)); // error: may expose variables outside of their declaration scope
}
}";
comp = CreateCompilation(sourceB, references: new[] { refA }, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersionB));
comp.VerifyEmitDiagnostics();
}
[Theory]
[CombinatorialData]
public void ParameterScope_01(bool useCompilationReference)
{
var sourceA =
@"public ref struct R
{
public R(ref int i) { }
}
public static class A
{
public static void F1(R x1, scoped R y1) { }
public static void F2(ref R x2, scoped ref R y2) { }
public static void F3(in R x3, scoped in R y3) { }
public static void F4(out R x4, scoped out R y4) { x4 = default; y4 = default; }
}";
var comp = CreateCompilation(sourceA, parseOptions: TestOptions.Regular10);
comp.VerifyEmitDiagnostics(
// (7,33): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater.
// public static void F1(R x1, scoped R y1) { }
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "scoped").WithArguments("ref fields", "11.0").WithLocation(7, 33),
// (8,37): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater.
// public static void F2(ref R x2, scoped ref R y2) { }
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "scoped").WithArguments("ref fields", "11.0").WithLocation(8, 37),
// (9,36): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater.
// public static void F3(in R x3, scoped in R y3) { }
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "scoped").WithArguments("ref fields", "11.0").WithLocation(9, 36),
// (10,37): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater.
// public static void F4(out R x4, scoped out R y4) { x4 = default; y4 = default; }
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "scoped").WithArguments("ref fields", "11.0").WithLocation(10, 37));
verify(comp, useUpdatedEscapeRules: false);
comp = CreateCompilation(sourceA);
comp.VerifyEmitDiagnostics();
var refA = AsReference(comp, useCompilationReference);
var sourceB =
@"static class B
{
static void F(ref R x)
{
int i = 0;
R y = new R(ref i);
A.F2(ref x, ref y);
}
}";
comp = CreateCompilation(sourceB, references: new[] { refA });
comp.VerifyEmitDiagnostics(
// (7,9): error CS8350: This combination of arguments to 'A.F2(ref R, scoped ref R)' is disallowed because it may expose variables referenced by parameter 'y2' outside of their declaration scope
// A.F2(ref x, ref y);
Diagnostic(ErrorCode.ERR_CallArgMixing, "A.F2(ref x, ref y)").WithArguments("A.F2(ref R, scoped ref R)", "y2").WithLocation(7, 9),
// (7,25): error CS8352: Cannot use variable 'y' in this context because it may expose referenced variables outside of their declaration scope
// A.F2(ref x, ref y);
Diagnostic(ErrorCode.ERR_EscapeVariable, "y").WithArguments("y").WithLocation(7, 25));
verify(comp, useUpdatedEscapeRules: true);
static void verify(CSharpCompilation comp, bool useUpdatedEscapeRules)
{
var parameters = comp.GetMember<MethodSymbol>("A.F1").Parameters;
VerifyParameterSymbol(parameters[0], "R x1", RefKind.None, ScopedKind.None);
VerifyParameterSymbol(parameters[1], "scoped R y1", RefKind.None, ScopedKind.ScopedValue);
parameters = comp.GetMember<MethodSymbol>("A.F2").Parameters;
VerifyParameterSymbol(parameters[0], "ref R x2", RefKind.Ref, ScopedKind.None);
VerifyParameterSymbol(parameters[1], "scoped ref R y2", RefKind.Ref, ScopedKind.ScopedRef);
parameters = comp.GetMember<MethodSymbol>("A.F3").Parameters;
VerifyParameterSymbol(parameters[0], "in R x3", RefKind.In, ScopedKind.None);
VerifyParameterSymbol(parameters[1], "scoped in R y3", RefKind.In, ScopedKind.ScopedRef);
parameters = comp.GetMember<MethodSymbol>("A.F4").Parameters;
VerifyParameterSymbol(parameters[0], "out R x4", RefKind.Out, useUpdatedEscapeRules ? ScopedKind.ScopedRef : ScopedKind.None);
VerifyParameterSymbol(parameters[1], "out R y4", RefKind.Out, ScopedKind.ScopedRef);
}
}
[Fact]
public void ParameterScope_02()
{
var source =
@"ref struct A<T>
{
A(scoped ref T t) { }
T this[scoped in object o] => default;
public static implicit operator B<T>(scoped in A<T> a) => default;
}
struct B<T>
{
}";
var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10);
comp.VerifyEmitDiagnostics(
// (3,7): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater.
// A(scoped ref T t) { }
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "scoped").WithArguments("ref fields", "11.0").WithLocation(3, 7),
// (4,12): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater.
// T this[scoped in object o] => default;
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "scoped").WithArguments("ref fields", "11.0").WithLocation(4, 12),
// (5,42): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater.
// public static implicit operator B<T>(scoped in A<T> a) => default;
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "scoped").WithArguments("ref fields", "11.0").WithLocation(5, 42));
verify(comp);
comp = CreateCompilation(source);
comp.VerifyEmitDiagnostics();
verify(comp);
static void verify(CSharpCompilation comp)
{
VerifyParameterSymbol(comp.GetMember<NamedTypeSymbol>("A").Constructors.Single(c => !c.IsImplicitlyDeclared).Parameters[0], "scoped ref T t", RefKind.Ref, ScopedKind.ScopedRef);
VerifyParameterSymbol(comp.GetMember<PropertySymbol>("A.this[]").GetMethod.Parameters[0], "scoped in System.Object o", RefKind.In, ScopedKind.ScopedRef);
}
}
[Fact]
public void ParameterScope_03()
{
var source =
@"ref struct R { }
class Program
{
static void Main()
{
#pragma warning disable 8321
static void L1(R x1, scoped R y1) { }
static void L2(ref int x2, scoped ref int y2) { }
static void L3(in int x3, scoped in int y3) { }
static void L4(out int x4, scoped out int y4) { x4 = 0; y4 = 0; }
static void L5(ref R x5, scoped ref R y5) { }
static void L6(in R x6, scoped in R y6) { }
static void L7(out R x7, scoped out R y7) { x7 = default; y7 = default; }
}
}";
var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10);
comp.VerifyEmitDiagnostics(
// (7,30): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater.
// static void L1(R x1, scoped R y1) { }
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "scoped").WithArguments("ref fields", "11.0").WithLocation(7, 30),
// (8,36): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater.
// static void L2(ref int x2, scoped ref int y2) { }
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "scoped").WithArguments("ref fields", "11.0").WithLocation(8, 36),
// (9,35): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater.
// static void L3(in int x3, scoped in int y3) { }
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "scoped").WithArguments("ref fields", "11.0").WithLocation(9, 35),
// (10,36): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater.
// static void L4(out int x4, scoped out int y4) { x4 = 0; y4 = 0; }
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "scoped").WithArguments("ref fields", "11.0").WithLocation(10, 36),
// (11,34): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater.
// static void L5(ref R x5, scoped ref R y5) { }
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "scoped").WithArguments("ref fields", "11.0").WithLocation(11, 34),
// (12,33): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater.
// static void L6(in R x6, scoped in R y6) { }
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "scoped").WithArguments("ref fields", "11.0").WithLocation(12, 33),
// (13,34): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater.
// static void L7(out R x7, scoped out R y7) { x7 = default; y7 = default; }
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "scoped").WithArguments("ref fields", "11.0").WithLocation(13, 34));
verify(comp, useUpdatedEscapeRules: false);
comp = CreateCompilation(source);
comp.VerifyEmitDiagnostics();
verify(comp, useUpdatedEscapeRules: true);
static void verify(CSharpCompilation comp, bool useUpdatedEscapeRules)
{
var tree = comp.SyntaxTrees[0];
var model = comp.GetSemanticModel(tree);
var decls = tree.GetRoot().DescendantNodes().OfType<LocalFunctionStatementSyntax>().ToArray();
var localFunctions = decls.Select(d => model.GetDeclaredSymbol(d).GetSymbol<LocalFunctionSymbol>()).ToArray();
VerifyParameterSymbol(localFunctions[0].Parameters[0], "R x1", RefKind.None, ScopedKind.None);
VerifyParameterSymbol(localFunctions[0].Parameters[1], "scoped R y1", RefKind.None, ScopedKind.ScopedValue);
VerifyParameterSymbol(localFunctions[1].Parameters[0], "ref System.Int32 x2", RefKind.Ref, ScopedKind.None);
VerifyParameterSymbol(localFunctions[1].Parameters[1], "scoped ref System.Int32 y2", RefKind.Ref, ScopedKind.ScopedRef);
VerifyParameterSymbol(localFunctions[2].Parameters[0], "in System.Int32 x3", RefKind.In, ScopedKind.None);
VerifyParameterSymbol(localFunctions[2].Parameters[1], "scoped in System.Int32 y3", RefKind.In, ScopedKind.ScopedRef);
VerifyParameterSymbol(localFunctions[3].Parameters[0], "out System.Int32 x4", RefKind.Out, useUpdatedEscapeRules ? ScopedKind.ScopedRef : ScopedKind.None);
VerifyParameterSymbol(localFunctions[3].Parameters[1], "out System.Int32 y4", RefKind.Out, ScopedKind.ScopedRef);
VerifyParameterSymbol(localFunctions[4].Parameters[0], "ref R x5", RefKind.Ref, ScopedKind.None);
VerifyParameterSymbol(localFunctions[4].Parameters[1], "scoped ref R y5", RefKind.Ref, ScopedKind.ScopedRef);
VerifyParameterSymbol(localFunctions[5].Parameters[0], "in R x6", RefKind.In, ScopedKind.None);
VerifyParameterSymbol(localFunctions[5].Parameters[1], "scoped in R y6", RefKind.In, ScopedKind.ScopedRef);
VerifyParameterSymbol(localFunctions[6].Parameters[0], "out R x7", RefKind.Out, useUpdatedEscapeRules ? ScopedKind.ScopedRef : ScopedKind.None);
VerifyParameterSymbol(localFunctions[6].Parameters[1], "out R y7", RefKind.Out, ScopedKind.ScopedRef);
}
}
[Fact]
public void ParameterScope_04()
{
var source =
@"ref struct R { }
class Program
{
static void Main()
{
var f1 = (R x1, scoped R y1) => { };
var f2 = (ref int x2, scoped ref int y2) => { };
var f3 = (in int x3, scoped in int y3) => { };
var f4 = (out int x4, scoped out int y4, [System.Diagnostics.CodeAnalysis.UnscopedRefAttribute] out int z4) => { x4 = 0; y4 = 0; z4 = 0; };
var f5 = (ref R x5, scoped ref R y5) => { };
var f6 = (in R x6, scoped in R y6) => { };
var f7 = (out R x7, scoped out R y7) => { x7 = default; y7 = default; };
}
}";
var comp = CreateCompilation(new[] { source, UnscopedRefAttributeDefinition }, parseOptions: TestOptions.Regular10);
comp.VerifyEmitDiagnostics(
// (6,25): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater.
// var f1 = (R x1, scoped R y1) => { };
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "scoped").WithArguments("ref fields", "11.0").WithLocation(6, 25),
// (7,31): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater.
// var f2 = (ref int x2, scoped ref int y2) => { };
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "scoped").WithArguments("ref fields", "11.0").WithLocation(7, 31),
// (8,30): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater.
// var f3 = (in int x3, scoped in int y3) => { };
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "scoped").WithArguments("ref fields", "11.0").WithLocation(8, 30),
// (9,31): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater.
// var f4 = (out int x4, scoped out int y4, [System.Diagnostics.CodeAnalysis.UnscopedRefAttribute] out int z4) => { x4 = 0; y4 = 0; z4 = 0; };
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "scoped").WithArguments("ref fields", "11.0").WithLocation(9, 31),
// (9,51): error CS9063: UnscopedRefAttribute cannot be applied to this item because it is unscoped by default.
// var f4 = (out int x4, scoped out int y4, [System.Diagnostics.CodeAnalysis.UnscopedRefAttribute] out int z4) => { x4 = 0; y4 = 0; z4 = 0; };
Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedTarget, "System.Diagnostics.CodeAnalysis.UnscopedRefAttribute").WithLocation(9, 51),
// (10,29): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater.
// var f5 = (ref R x5, scoped ref R y5) => { };
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "scoped").WithArguments("ref fields", "11.0").WithLocation(10, 29),
// (11,28): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater.
// var f6 = (in R x6, scoped in R y6) => { };
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "scoped").WithArguments("ref fields", "11.0").WithLocation(11, 28),
// (12,29): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater.
// var f7 = (out R x7, scoped out R y7) => { x7 = default; y7 = default; };
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "scoped").WithArguments("ref fields", "11.0").WithLocation(12, 29));
verify(comp, useUpdatedEscapeRules: false);
comp = CreateCompilation(new[] { source, UnscopedRefAttributeDefinition });
comp.VerifyEmitDiagnostics();
verify(comp, useUpdatedEscapeRules: true);
static void verify(CSharpCompilation comp, bool useUpdatedEscapeRules)
{
var tree = comp.SyntaxTrees[0];
var model = comp.GetSemanticModel(tree);
var delegateTypesAndLambdas = tree.GetRoot().DescendantNodes().OfType<VariableDeclaratorSyntax>().Select(d => getDelegateTypeAndLambda(model, d)).ToArray();
verifyParameter(delegateTypesAndLambdas[0], 0, "R", "x1", RefKind.None, ScopedKind.None, false);
verifyParameter(delegateTypesAndLambdas[0], 1, "scoped R", "y1", RefKind.None, ScopedKind.ScopedValue, false);
verifyParameter(delegateTypesAndLambdas[1], 0, "ref System.Int32", "x2", RefKind.Ref, ScopedKind.None, false);
verifyParameter(delegateTypesAndLambdas[1], 1, "scoped ref System.Int32", "y2", RefKind.Ref, ScopedKind.ScopedRef, false);
verifyParameter(delegateTypesAndLambdas[2], 0, "in System.Int32", "x3", RefKind.In, ScopedKind.None, false);
verifyParameter(delegateTypesAndLambdas[2], 1, "scoped in System.Int32", "y3", RefKind.In, ScopedKind.ScopedRef, false);
verifyParameter(delegateTypesAndLambdas[3], 0, "out System.Int32", "x4", RefKind.Out, useUpdatedEscapeRules ? ScopedKind.ScopedRef : ScopedKind.None, false);
verifyParameter(delegateTypesAndLambdas[3], 1, "out System.Int32", "y4", RefKind.Out, ScopedKind.ScopedRef, false);
verifyParameter(delegateTypesAndLambdas[3], 2, "out System.Int32", "z4", RefKind.Out, ScopedKind.None, true);
verifyParameter(delegateTypesAndLambdas[4], 0, "ref R", "x5", RefKind.Ref, ScopedKind.None, false);
verifyParameter(delegateTypesAndLambdas[4], 1, "scoped ref R", "y5", RefKind.Ref, ScopedKind.ScopedRef, false);
verifyParameter(delegateTypesAndLambdas[5], 0, "in R", "x6", RefKind.In, ScopedKind.None, false);
verifyParameter(delegateTypesAndLambdas[5], 1, "scoped in R", "y6", RefKind.In, ScopedKind.ScopedRef, false);
verifyParameter(delegateTypesAndLambdas[6], 0, "out R", "x7", RefKind.Out, useUpdatedEscapeRules ? ScopedKind.ScopedRef : ScopedKind.None, false);
verifyParameter(delegateTypesAndLambdas[6], 1, "out R", "y7", RefKind.Out, ScopedKind.ScopedRef, false);
}
static void verifyParameter((NamedTypeSymbol, LambdaSymbol) delegateTypeAndLambda, int parameterIndex, string expectedDisplayType, string expectedDisplayName, RefKind expectedRefKind, ScopedKind expectedScope, bool expectedHasUnscopedRefAttribute)
{
var (delegateType, lambda) = delegateTypeAndLambda;
VerifyParameterSymbol(delegateType.DelegateInvokeMethod.Parameters[parameterIndex], $"{expectedDisplayType} arg{parameterIndex + 1}", expectedRefKind, expectedScope, expectedHasUnscopedRefAttribute);
VerifyParameterSymbol(lambda.Parameters[parameterIndex], $"{expectedDisplayType} {expectedDisplayName}", expectedRefKind, expectedScope, expectedHasUnscopedRefAttribute);
}
static (NamedTypeSymbol, LambdaSymbol) getDelegateTypeAndLambda(SemanticModel model, VariableDeclaratorSyntax decl)
{
var delegateType = (NamedTypeSymbol)model.GetDeclaredSymbol(decl).GetSymbol<LocalSymbol>().Type;
var value = decl.DescendantNodes().OfType<ParenthesizedLambdaExpressionSyntax>().Single();
var lambda = model.GetSymbolInfo(value).Symbol.GetSymbol<LambdaSymbol>();
return (delegateType, lambda);
}
}
[Fact]
public void ParameterScope_05()
{
var source =
@"ref struct R { }
delegate void D1(scoped R r1);
delegate void D2(scoped ref R r2);
";
var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10);
comp.VerifyEmitDiagnostics(
// (2,18): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater.
// delegate void D1(scoped R r1);
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "scoped").WithArguments("ref fields", "11.0").WithLocation(2, 18),
// (3,18): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater.
// delegate void D2(scoped ref R r2);
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "scoped").WithArguments("ref fields", "11.0").WithLocation(3, 18));
verify(comp, useUpdatedEscapeRules: false);
comp = CreateCompilation(source);
comp.VerifyEmitDiagnostics();
verify(comp, useUpdatedEscapeRules: true);
static void verify(CSharpCompilation comp, bool useUpdatedEscapeRules)
{
VerifyParameterSymbol(comp.GetMember<NamedTypeSymbol>("D1").DelegateInvokeMethod.Parameters[0], "scoped R r1", RefKind.None, ScopedKind.ScopedValue);
VerifyParameterSymbol(comp.GetMember<NamedTypeSymbol>("D2").DelegateInvokeMethod.Parameters[0], "scoped ref R r2", RefKind.Ref, ScopedKind.ScopedRef);
}
}
[Fact]
public void ParameterScope_06()
{
var source =
@"ref struct R { }
class Program
{
static void F1(scoped R r1) { }
static void F2(scoped ref R x, scoped ref int y) { }
static ref R F3(ref R r) => throw null;
static unsafe void Main()
{
delegate*<scoped R, void> f1 = &F1;
delegate*<scoped ref R, scoped ref int, void> f2 = &F2;
delegate*<ref R, ref R> f3 = &F3;
}
}";
var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10, options: TestOptions.UnsafeReleaseExe);
comp.VerifyEmitDiagnostics(
// (4,20): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater.
// static void F1(scoped R r1) { }
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "scoped").WithArguments("ref fields", "11.0").WithLocation(4, 20),
// (5,20): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater.
// static void F2(scoped ref R x, scoped ref int y) { }
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "scoped").WithArguments("ref fields", "11.0").WithLocation(5, 20),
// (5,36): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater.
// static void F2(scoped ref R x, scoped ref int y) { }
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "scoped").WithArguments("ref fields", "11.0").WithLocation(5, 36),
// (9,19): error CS8755: 'scoped' cannot be used as a modifier on a function pointer parameter.
// delegate*<scoped R, void> f1 = &F1;
Diagnostic(ErrorCode.ERR_BadFuncPointerParamModifier, "scoped").WithArguments("scoped").WithLocation(9, 19),
// (10,19): error CS8755: 'scoped' cannot be used as a modifier on a function pointer parameter.
// delegate*<scoped ref R, scoped ref int, void> f2 = &F2;
Diagnostic(ErrorCode.ERR_BadFuncPointerParamModifier, "scoped").WithArguments("scoped").WithLocation(10, 19),
// (10,33): error CS8755: 'scoped' cannot be used as a modifier on a function pointer parameter.
// delegate*<scoped ref R, scoped ref int, void> f2 = &F2;
Diagnostic(ErrorCode.ERR_BadFuncPointerParamModifier, "scoped").WithArguments("scoped").WithLocation(10, 33)
);
verify(comp, useUpdatedEscapeRules: false);
comp = CreateCompilation(source, options: TestOptions.UnsafeReleaseExe);
comp.VerifyEmitDiagnostics(
// (9,19): error CS8755: 'scoped' cannot be used as a modifier on a function pointer parameter.
// delegate*<scoped R, void> f1 = &F1;
Diagnostic(ErrorCode.ERR_BadFuncPointerParamModifier, "scoped").WithArguments("scoped").WithLocation(9, 19),
// (10,19): error CS8755: 'scoped' cannot be used as a modifier on a function pointer parameter.
// delegate*<scoped ref R, scoped ref int, void> f2 = &F2;
Diagnostic(ErrorCode.ERR_BadFuncPointerParamModifier, "scoped").WithArguments("scoped").WithLocation(10, 19),
// (10,33): error CS8755: 'scoped' cannot be used as a modifier on a function pointer parameter.
// delegate*<scoped ref R, scoped ref int, void> f2 = &F2;
Diagnostic(ErrorCode.ERR_BadFuncPointerParamModifier, "scoped").WithArguments("scoped").WithLocation(10, 33)
);
verify(comp, useUpdatedEscapeRules: true);
static void verify(CSharpCompilation comp, bool useUpdatedEscapeRules)
{
var tree = comp.SyntaxTrees[0];
var model = comp.GetSemanticModel(tree);
var decls = tree.GetRoot().DescendantNodes().OfType<VariableDeclaratorSyntax>().ToArray();
var methods = decls.Select(d => ((FunctionPointerTypeSymbol)model.GetDeclaredSymbol(d).GetSymbol<LocalSymbol>().Type).Signature).ToArray();
VerifyParameterSymbol(methods[0].Parameters[0], "R", RefKind.None, ScopedKind.None);
VerifyParameterSymbol(methods[1].Parameters[0], "ref R", RefKind.Ref, ScopedKind.None);
VerifyParameterSymbol(methods[1].Parameters[1], "ref System.Int32", RefKind.Ref, ScopedKind.None);
VerifyParameterSymbol(methods[2].Parameters[0], "ref R", RefKind.Ref, ScopedKind.None);
}
}
[Fact]
public void ParameterScope_07()
{
var source =
@"ref struct R { }
class Program
{
static void F0(scoped R r) { }
static void F3(scoped ref R r) { }
static void F6(scoped in R r) { }
static void F9(scoped out R r) { r = default; }
}";
var comp = CreateCompilation(source);
comp.VerifyEmitDiagnostics();
VerifyParameterSymbol(comp.GetMember<MethodSymbol>("Program.F0").Parameters[0], "scoped R r", RefKind.None, ScopedKind.ScopedValue);
VerifyParameterSymbol(comp.GetMember<MethodSymbol>("Program.F3").Parameters[0], "scoped ref R r", RefKind.Ref, ScopedKind.ScopedRef);
VerifyParameterSymbol(comp.GetMember<MethodSymbol>("Program.F6").Parameters[0], "scoped in R r", RefKind.In, ScopedKind.ScopedRef);
VerifyParameterSymbol(comp.GetMember<MethodSymbol>("Program.F9").Parameters[0], "out R r", RefKind.Out, ScopedKind.ScopedRef);
}
[Fact]
public void ParameterScope_08()
{
var source =
@"ref struct R { }
class Program
{
static void Main()
{
var f1 = (scoped scoped R r) => { };
var f2 = (ref scoped scoped R r) => { };
var f3 = (scoped scoped ref R r) => { };
}
}";
var comp = CreateCompilation(source);
comp.VerifyEmitDiagnostics(
// (6,19): error CS0103: The name 'scoped' does not exist in the current context
// var f1 = (scoped scoped R r) => { };
Diagnostic(ErrorCode.ERR_NameNotInContext, "scoped").WithArguments("scoped").WithLocation(6, 19),
// (6,26): error CS1026: ) expected
// var f1 = (scoped scoped R r) => { };
Diagnostic(ErrorCode.ERR_CloseParenExpected, "scoped").WithLocation(6, 26),
// (6,26): error CS1002: ; expected
// var f1 = (scoped scoped R r) => { };
Diagnostic(ErrorCode.ERR_SemicolonExpected, "scoped").WithLocation(6, 26),
// (6,35): warning CS0168: The variable 'r' is declared but never used
// var f1 = (scoped scoped R r) => { };
Diagnostic(ErrorCode.WRN_UnreferencedVar, "r").WithArguments("r").WithLocation(6, 35),
// (6,36): error CS1002: ; expected
// var f1 = (scoped scoped R r) => { };
Diagnostic(ErrorCode.ERR_SemicolonExpected, ")").WithLocation(6, 36),
// (6,36): error CS1513: } expected
// var f1 = (scoped scoped R r) => { };
Diagnostic(ErrorCode.ERR_RbraceExpected, ")").WithLocation(6, 36),
// (7,19): error CS1525: Invalid expression term 'ref'
// var f2 = (ref scoped scoped R r) => { };
Diagnostic(ErrorCode.ERR_InvalidExprTerm, "ref scoped").WithArguments("ref").WithLocation(7, 19),
// (7,19): error CS1073: Unexpected token 'ref'
// var f2 = (ref scoped scoped R r) => { };
Diagnostic(ErrorCode.ERR_UnexpectedToken, "ref").WithArguments("ref").WithLocation(7, 19),
// (7,30): error CS1026: ) expected
// var f2 = (ref scoped scoped R r) => { };
Diagnostic(ErrorCode.ERR_CloseParenExpected, "scoped").WithLocation(7, 30),
// (7,30): error CS1002: ; expected
// var f2 = (ref scoped scoped R r) => { };
Diagnostic(ErrorCode.ERR_SemicolonExpected, "scoped").WithLocation(7, 30),
// (7,39): error CS0128: A local variable or function named 'r' is already defined in this scope
// var f2 = (ref scoped scoped R r) => { };
Diagnostic(ErrorCode.ERR_LocalDuplicate, "r").WithArguments("r").WithLocation(7, 39),
// (7,39): warning CS0168: The variable 'r' is declared but never used
// var f2 = (ref scoped scoped R r) => { };
Diagnostic(ErrorCode.WRN_UnreferencedVar, "r").WithArguments("r").WithLocation(7, 39),
// (7,40): error CS1002: ; expected
// var f2 = (ref scoped scoped R r) => { };
Diagnostic(ErrorCode.ERR_SemicolonExpected, ")").WithLocation(7, 40),
// (7,40): error CS1513: } expected
// var f2 = (ref scoped scoped R r) => { };
Diagnostic(ErrorCode.ERR_RbraceExpected, ")").WithLocation(7, 40),
// (8,19): error CS0103: The name 'scoped' does not exist in the current context
// var f3 = (scoped scoped ref R r) => { };
Diagnostic(ErrorCode.ERR_NameNotInContext, "scoped").WithArguments("scoped").WithLocation(8, 19),
// (8,26): error CS1026: ) expected
// var f3 = (scoped scoped ref R r) => { };
Diagnostic(ErrorCode.ERR_CloseParenExpected, "scoped").WithLocation(8, 26),
// (8,26): error CS1002: ; expected
// var f3 = (scoped scoped ref R r) => { };
Diagnostic(ErrorCode.ERR_SemicolonExpected, "scoped").WithLocation(8, 26),
// (8,39): error CS0128: A local variable or function named 'r' is already defined in this scope
// var f3 = (scoped scoped ref R r) => { };
Diagnostic(ErrorCode.ERR_LocalDuplicate, "r").WithArguments("r").WithLocation(8, 39),
// (8,39): error CS8174: A declaration of a by-reference variable must have an initializer
// var f3 = (scoped scoped ref R r) => { };
Diagnostic(ErrorCode.ERR_ByReferenceVariableMustBeInitialized, "r").WithLocation(8, 39),
// (8,39): warning CS0168: The variable 'r' is declared but never used
// var f3 = (scoped scoped ref R r) => { };
Diagnostic(ErrorCode.WRN_UnreferencedVar, "r").WithArguments("r").WithLocation(8, 39),
// (8,40): error CS1002: ; expected
// var f3 = (scoped scoped ref R r) => { };
Diagnostic(ErrorCode.ERR_SemicolonExpected, ")").WithLocation(8, 40),
// (8,40): error CS1513: } expected
// var f3 = (scoped scoped ref R r) => { };
Diagnostic(ErrorCode.ERR_RbraceExpected, ")").WithLocation(8, 40)
);
}
[Fact]
public void ParameterScope_09()
{
var source =
@"ref struct @scoped { }
class Program
{
static void F0(scoped s) { }
static void F1(scoped scoped s) { }
static void F2(ref scoped s) { }
static void F4(scoped ref scoped s) { }
static void F5(in scoped s) { }
static void F7(scoped in scoped s) { }
static void F8(out scoped s) { s = default; }
static void FA(scoped out scoped s) { s = default; }
}";
var comp = CreateCompilation(source);
comp.VerifyEmitDiagnostics();
VerifyParameterSymbol(comp.GetMember<MethodSymbol>("Program.F0").Parameters[0], "scoped s", RefKind.None, ScopedKind.None);
VerifyParameterSymbol(comp.GetMember<MethodSymbol>("Program.F1").Parameters[0], "scoped scoped s", RefKind.None, ScopedKind.ScopedValue);
VerifyParameterSymbol(comp.GetMember<MethodSymbol>("Program.F2").Parameters[0], "ref scoped s", RefKind.Ref, ScopedKind.None);
VerifyParameterSymbol(comp.GetMember<MethodSymbol>("Program.F4").Parameters[0], "scoped ref scoped s", RefKind.Ref, ScopedKind.ScopedRef);
VerifyParameterSymbol(comp.GetMember<MethodSymbol>("Program.F5").Parameters[0], "in scoped s", RefKind.In, ScopedKind.None);
VerifyParameterSymbol(comp.GetMember<MethodSymbol>("Program.F7").Parameters[0], "scoped in scoped s", RefKind.In, ScopedKind.ScopedRef);
VerifyParameterSymbol(comp.GetMember<MethodSymbol>("Program.F8").Parameters[0], "out scoped s", RefKind.Out, ScopedKind.ScopedRef);
VerifyParameterSymbol(comp.GetMember<MethodSymbol>("Program.FA").Parameters[0], "out scoped s", RefKind.Out, ScopedKind.ScopedRef);
}
[WorkItem(62080, "https://github.com/dotnet/roslyn/issues/62080")]
[Fact]
public void ParameterScope_11()
{
var source =
@"ref struct R { }
delegate R D1(R r);
delegate R D2(scoped R r);
class Program
{
static void Main()
{
D1 d1 = r1 => r1;
D2 d2 = r2 => r2;
}
}";
var comp = CreateCompilation(source);
comp.VerifyEmitDiagnostics(
// (9,17): error CS8986: The 'scoped' modifier of parameter 'r2' doesn't match target 'D2'.
// D2 d2 = r2 => r2;
Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "r2 => r2").WithArguments("r2", "D2").WithLocation(9, 17));
var tree = comp.SyntaxTrees[0];
var model = comp.GetSemanticModel(tree);
var lambdas = tree.GetRoot().DescendantNodes().OfType<SimpleLambdaExpressionSyntax>().Select(e => model.GetSymbolInfo(e).Symbol.GetSymbol<LambdaSymbol>()).ToArray();
VerifyParameterSymbol(lambdas[0].Parameters[0], "R r1", RefKind.None, ScopedKind.None);
VerifyParameterSymbol(lambdas[1].Parameters[0], "R r2", RefKind.None, ScopedKind.None);
}
[Fact]
public void ParameterScope_12()
{
var source0 =
@".assembly extern mscorlib { .ver 4:0:0:0 .publickeytoken = (B7 7A 5C 56 19 34 E0 89) }
.assembly '<<GeneratedFileName>>' { }
.module '<<GeneratedFileName>>.dll'
.custom instance void System.Runtime.CompilerServices.RefSafetyRulesAttribute::.ctor(int32) = { int32(11) }
.class private System.Runtime.CompilerServices.RefSafetyRulesAttribute extends [mscorlib]System.Attribute
{
.method public hidebysig specialname rtspecialname instance void .ctor(int32 version) cil managed { ret }
.field public int32 Version
}
.class private System.Runtime.CompilerServices.ScopedRefAttribute extends [mscorlib]System.Attribute
{
.method public hidebysig specialname rtspecialname instance void .ctor() cil managed { ret }
}
.class public A
{
.method public static void F1([out] int32& i)
{
.param [1]
.custom instance void System.Runtime.CompilerServices.ScopedRefAttribute::.ctor() = ( 01 00 00 00 ) // ScopedRefAttribute()
ldnull
throw
}
}
";
var ref0 = CompileIL(source0, prependDefaultHeader: false);
var source1 =
@"class Program
{
static void Main()
{
int i;
A.F1(out i);
}
}";
var comp = CreateCompilation(source1, references: new[] { ref0 });
comp.VerifyDiagnostics();
VerifyParameterSymbol(comp.GetMember<PEMethodSymbol>("A.F1").Parameters[0], "out System.Int32 i", RefKind.Out, ScopedKind.ScopedRef);
}
[WorkItem(62691, "https://github.com/dotnet/roslyn/issues/62691")]
[CombinatorialData]
[Theory]
public void RefToRefStructParameter_01(bool useCompilationReference)
{
var sourceA =
@"public ref struct R { }
public class A
{
public static void F(R a, ref R b, in R c, out R d) { d = default; }
}";
var comp = CreateCompilation(sourceA);
comp.VerifyDiagnostics();
var refA = AsReference(comp, useCompilationReference);
var sourceB =
@"class B
{
static void Main()
{
R a = new R();
R b = new R();
R c = new R();
scoped R d;
A.F(a, ref b, in c, out d);
}
}";
comp = CreateCompilation(sourceB, references: new[] { refA });
comp.VerifyEmitDiagnostics();
var parameters = comp.GetMember<MethodSymbol>("A.F").Parameters;
VerifyParameterSymbol(parameters[0], "R a", RefKind.None, ScopedKind.None);
VerifyParameterSymbol(parameters[1], "ref R b", RefKind.Ref, ScopedKind.None);
VerifyParameterSymbol(parameters[2], "in R c", RefKind.In, ScopedKind.None);
VerifyParameterSymbol(parameters[3], "out R d", RefKind.Out, ScopedKind.ScopedRef);
}
[WorkItem(62691, "https://github.com/dotnet/roslyn/issues/62691")]
[Fact]
public void RefToRefStructParameter_02()
{
var source =
@"ref struct R
{
public ref int F;
public R(ref int i) { F = ref i; }
}
class Program
{
static ref R F1()
{
int i = 42;
var r1 = new R(ref i);
return ref ReturnRef(ref r1);
}
static ref R F2(ref int i)
{
var r2 = new R(ref i);
return ref ReturnRef(ref r2);
}
// NB: there is actually no valid implementation here except to throw.
// With this signature, we will never be able to return any ref struct by reference.
static ref R ReturnRef(scoped ref R r) => throw null;
}";
var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70);
comp.VerifyDiagnostics();
VerifyParameterSymbol(comp.GetMember<MethodSymbol>("Program.ReturnRef").Parameters[0], "scoped ref R r", RefKind.Ref, ScopedKind.ScopedRef);
}
[Theory]
[InlineData(LanguageVersion.CSharp10)]
[InlineData(LanguageVersion.CSharp11)]
public void ThisScope(LanguageVersion languageVersion)
{
var source =
@"class C
{
public C() { }
void F1() { }
}
struct S1
{
public S1() { }
void F1() { }
readonly void F2() { }
}
ref struct R1
{
public R1() { }
void F1() { }
readonly void F2() { }
}
readonly struct S2
{
public S2() { }
void F1() { }
readonly void F2() { }
}
readonly ref struct R2
{
public R2() { }
void F1() { }
readonly void F2() { }
}";
var comp = CreateCompilation(source, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion));
comp.VerifyEmitDiagnostics();
VerifyParameterSymbol(comp.GetMember<MethodSymbol>("C..ctor").ThisParameter, "C this", RefKind.None, ScopedKind.None);
VerifyParameterSymbol(comp.GetMember<MethodSymbol>("C.F1").ThisParameter, "C this", RefKind.None, ScopedKind.None);
VerifyParameterSymbol(comp.GetMember<MethodSymbol>("S1..ctor").ThisParameter, "out S1 this", RefKind.Out, ScopedKind.ScopedRef);
VerifyParameterSymbol(comp.GetMember<MethodSymbol>("S1.F1").ThisParameter, "ref S1 this", RefKind.Ref, ScopedKind.ScopedRef);
VerifyParameterSymbol(comp.GetMember<MethodSymbol>("S1.F2").ThisParameter, "in S1 this", RefKind.In, ScopedKind.ScopedRef);
VerifyParameterSymbol(comp.GetMember<MethodSymbol>("R1..ctor").ThisParameter, "out R1 this", RefKind.Out, ScopedKind.ScopedRef);
VerifyParameterSymbol(comp.GetMember<MethodSymbol>("R1.F1").ThisParameter, "ref R1 this", RefKind.Ref, ScopedKind.ScopedRef);
VerifyParameterSymbol(comp.GetMember<MethodSymbol>("R1.F2").ThisParameter, "in R1 this", RefKind.In, ScopedKind.ScopedRef);
VerifyParameterSymbol(comp.GetMember<MethodSymbol>("S2..ctor").ThisParameter, "out S2 this", RefKind.Out, ScopedKind.ScopedRef);
VerifyParameterSymbol(comp.GetMember<MethodSymbol>("S2.F1").ThisParameter, "in S2 this", RefKind.In, ScopedKind.ScopedRef);
VerifyParameterSymbol(comp.GetMember<MethodSymbol>("S2.F2").ThisParameter, "in S2 this", RefKind.In, ScopedKind.ScopedRef);
VerifyParameterSymbol(comp.GetMember<MethodSymbol>("R2..ctor").ThisParameter, "out R2 this", RefKind.Out, ScopedKind.ScopedRef);
VerifyParameterSymbol(comp.GetMember<MethodSymbol>("R2.F1").ThisParameter, "in R2 this", RefKind.In, ScopedKind.ScopedRef);
VerifyParameterSymbol(comp.GetMember<MethodSymbol>("R2.F2").ThisParameter, "in R2 this", RefKind.In, ScopedKind.ScopedRef);
var type = comp.GetMember<NamedTypeSymbol>("S1");
var thisParameter = new ThisParameterSymbol(forMethod: null, type); // "this" parameter for property for instance.
VerifyParameterSymbol(thisParameter, "ref S1 this", RefKind.Ref, ScopedKind.ScopedRef);
bool useUpdatedEscapeRules = languageVersion == LanguageVersion.CSharp11;
Assert.Equal(useUpdatedEscapeRules, thisParameter.UseUpdatedEscapeRules);
// https://github.com/dotnet/roslyn/issues/62780: Test additional cases with [UnscopedRef].
}
[Fact]
public void ExtensionThisScope()
{
var source =
@"ref struct R<T> { }
static class Extensions
{
static void F0(this R<object> r) { }
static void F1(this scoped R<object> r) { }
static void F2<T>(scoped this R<T> r) { }
static void F3<T>(this scoped ref T t) where T : struct { }
}";
var comp = CreateCompilation(source);
comp.VerifyEmitDiagnostics(
// (6,23): error CS0246: The type or namespace name 'scoped' could not be found (are you missing a using directive or an assembly reference?)
// static void F2<T>(scoped this R<T> r) { }
Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "scoped").WithArguments("scoped").WithLocation(6, 23),
// (6,30): error CS1001: Identifier expected
// static void F2<T>(scoped this R<T> r) { }
Diagnostic(ErrorCode.ERR_IdentifierExpected, "this").WithLocation(6, 30),
// (6,30): error CS1003: Syntax error, ',' expected
// static void F2<T>(scoped this R<T> r) { }
Diagnostic(ErrorCode.ERR_SyntaxError, "this").WithArguments(",").WithLocation(6, 30),
// (6,30): error CS1100: Method 'F2' has a parameter modifier 'this' which is not on the first parameter
// static void F2<T>(scoped this R<T> r) { }
Diagnostic(ErrorCode.ERR_BadThisParam, "this").WithArguments("F2").WithLocation(6, 30)
);
VerifyParameterSymbol(comp.GetMember<MethodSymbol>("Extensions.F0").Parameters[0], "R<System.Object> r", RefKind.None, ScopedKind.None);
VerifyParameterSymbol(comp.GetMember<MethodSymbol>("Extensions.F1").Parameters[0], "scoped R<System.Object> r", RefKind.None, ScopedKind.ScopedValue);
VerifyParameterSymbol(comp.GetMember<MethodSymbol>("Extensions.F2").Parameters[0], "scoped", RefKind.None, ScopedKind.None);
VerifyParameterSymbol(comp.GetMember<MethodSymbol>("Extensions.F3").Parameters[0], "scoped ref T t", RefKind.Ref, ScopedKind.ScopedRef);
}
[Fact]
public void ParamsScope()
{
var source =
@"class Program
{
static void F2(params scoped object[] args) { }
}";
var comp = CreateCompilation(source);
comp.VerifyEmitDiagnostics(
// (4,20): error CS8986: The 'scoped' modifier can be used for refs and ref struct values only.
// static void F2(params scoped object[] args) { }
Diagnostic(ErrorCode.ERR_ScopedRefAndRefStructOnly, "params scoped object[] args").WithLocation(4, 20));
VerifyParameterSymbol(comp.GetMember<MethodSymbol>("Program.F2").Parameters[0], "scoped params System.Object[] args", RefKind.None, ScopedKind.ScopedValue);
}
[Theory]
[InlineData(LanguageVersion.CSharp10)]
[InlineData(LanguageVersion.CSharp11)]
public void ReturnTypeScope(LanguageVersion langVersion)
{
var source =
@"ref struct R { }
class Program
{
static scoped R F1<T>() => throw null;
static scoped ref R F2<T>() => throw null;
static void Main()
{
#pragma warning disable 8321
static scoped R L1<T>() => throw null;
static scoped ref readonly R L2<T>() => throw null;
}
}";
var comp = CreateCompilation(source, parseOptions: TestOptions.Regular.WithLanguageVersion(langVersion));
comp.VerifyDiagnostics(
// (4,21): error CS0106: The modifier 'scoped' is not valid for this item
// static scoped R F1<T>() => throw null;
Diagnostic(ErrorCode.ERR_BadMemberFlag, "F1").WithArguments("scoped").WithLocation(4, 21),
// (5,25): error CS0106: The modifier 'scoped' is not valid for this item
// static scoped ref R F2<T>() => throw null;
Diagnostic(ErrorCode.ERR_BadMemberFlag, "F2").WithArguments("scoped").WithLocation(5, 25),
// (9,16): error CS0106: The modifier 'scoped' is not valid for this item
// static scoped R L1<T>() => throw null;
Diagnostic(ErrorCode.ERR_BadMemberFlag, "scoped").WithArguments("scoped").WithLocation(9, 16),
// (10,16): error CS0106: The modifier 'scoped' is not valid for this item
// static scoped ref readonly R L2<T>() => throw null;
Diagnostic(ErrorCode.ERR_BadMemberFlag, "scoped").WithArguments("scoped").WithLocation(10, 16));
}
[Theory]
[InlineData(LanguageVersion.CSharp10)]
[InlineData(LanguageVersion.CSharp11)]
public void DelegateReturnTypeScope(LanguageVersion langVersion)
{
var source =
@"ref struct R { }
delegate ref scoped R D();
";
var comp = CreateCompilation(source, parseOptions: TestOptions.Regular.WithLanguageVersion(langVersion));
comp.VerifyEmitDiagnostics(
// (2,14): error CS0246: The type or namespace name 'scoped' could not be found (are you missing a using directive or an assembly reference?)
// delegate ref scoped R D();
Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "scoped").WithArguments("scoped").WithLocation(2, 14),
// (2,21): error CS0101: The namespace '<global namespace>' already contains a definition for 'R'
// delegate ref scoped R D();
Diagnostic(ErrorCode.ERR_DuplicateNameInNS, "R").WithArguments("R", "<global namespace>").WithLocation(2, 21),
// (2,23): error CS1003: Syntax error, '(' expected
// delegate ref scoped R D();
Diagnostic(ErrorCode.ERR_SyntaxError, "D").WithArguments("(").WithLocation(2, 23),
// (2,23): error CS0246: The type or namespace name 'D' could not be found (are you missing a using directive or an assembly reference?)
// delegate ref scoped R D();
Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "D").WithArguments("D").WithLocation(2, 23),
// (2,24): error CS1001: Identifier expected
// delegate ref scoped R D();
Diagnostic(ErrorCode.ERR_IdentifierExpected, "(").WithLocation(2, 24),
// (2,24): error CS1003: Syntax error, ',' expected
// delegate ref scoped R D();
Diagnostic(ErrorCode.ERR_SyntaxError, "(").WithArguments(",").WithLocation(2, 24),
// (2,25): error CS8124: Tuple must contain at least two elements.
// delegate ref scoped R D();
Diagnostic(ErrorCode.ERR_TupleTooFewElements, ")").WithLocation(2, 25),
// (2,26): error CS1001: Identifier expected
// delegate ref scoped R D();
Diagnostic(ErrorCode.ERR_IdentifierExpected, ";").WithLocation(2, 26),
// (2,26): error CS1026: ) expected
// delegate ref scoped R D();
Diagnostic(ErrorCode.ERR_CloseParenExpected, ";").WithLocation(2, 26)
);
}
[Theory]
[InlineData(LanguageVersion.CSharp10)]
[InlineData(LanguageVersion.CSharp11)]
public void TypeScopeModifier_01(LanguageVersion langVersion)
{
var source =
@"scoped struct A { }
scoped ref struct B { }
scoped readonly ref struct C { }
";
var comp = CreateCompilation(source, parseOptions: TestOptions.Regular.WithLanguageVersion(langVersion));
comp.VerifyDiagnostics(
// (1,1): error CS0246: The type or namespace name 'scoped' could not be found (are you missing a using directive or an assembly reference?)
// scoped struct A { }
Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "scoped").WithArguments("scoped").WithLocation(1, 1),
// (1,8): error CS1001: Identifier expected
// scoped struct A { }
Diagnostic(ErrorCode.ERR_IdentifierExpected, "struct").WithLocation(1, 8),
// (1,8): error CS1002: ; expected
// scoped struct A { }
Diagnostic(ErrorCode.ERR_SemicolonExpected, "struct").WithLocation(1, 8),
// (2,12): error CS1031: Type expected
// scoped ref struct B { }
Diagnostic(ErrorCode.ERR_TypeExpected, "struct").WithLocation(2, 12),
// (3,8): error CS1585: Member modifier 'readonly' must precede the member type and name
// scoped readonly ref struct C { }
Diagnostic(ErrorCode.ERR_BadModifierLocation, "readonly").WithArguments("readonly").WithLocation(3, 8)
);
}
[Theory]
[InlineData(LanguageVersion.CSharp10)]
[InlineData(LanguageVersion.CSharp11)]
public void TypeScopeModifier_02(LanguageVersion langVersion)
{
var source =
@"scoped record A { }
scoped readonly record struct B;
readonly scoped record struct C();
";
var comp = CreateCompilation(source, parseOptions: TestOptions.Regular.WithLanguageVersion(langVersion));
comp.VerifyDiagnostics(
// (1,8): error CS0118: 'record' is a variable but is used like a type
// scoped record A { }
Diagnostic(ErrorCode.ERR_BadSKknown, "record").WithArguments("record", "variable", "type").WithLocation(1, 8),
// (1,15): error CS0116: A namespace cannot directly contain members such as fields, methods or statements
// scoped record A { }
Diagnostic(ErrorCode.ERR_NamespaceUnexpected, "A").WithLocation(1, 15),
// (1,15): error CS0106: The modifier 'scoped' is not valid for this item
// scoped record A { }
Diagnostic(ErrorCode.ERR_BadMemberFlag, "A").WithArguments("scoped").WithLocation(1, 15),
// (1,15): error CS0548: '<invalid-global-code>.A': property or indexer must have at least one accessor
// scoped record A { }
Diagnostic(ErrorCode.ERR_PropertyWithNoAccessors, "A").WithArguments("<invalid-global-code>.A").WithLocation(1, 15),
// (2,8): error CS1585: Member modifier 'readonly' must precede the member type and name
// scoped readonly record struct B;
Diagnostic(ErrorCode.ERR_BadModifierLocation, "readonly").WithArguments("readonly").WithLocation(2, 8),
// (3,1): error CS8803: Top-level statements must precede namespace and type declarations.
// readonly scoped record struct C();
Diagnostic(ErrorCode.ERR_TopLevelStatementAfterNamespaceOrType, "readonly scoped record ").WithLocation(3, 1),
// (3,1): error CS0106: The modifier 'readonly' is not valid for this item
// readonly scoped record struct C();
Diagnostic(ErrorCode.ERR_BadMemberFlag, "readonly").WithArguments("readonly").WithLocation(3, 1),
// (3,10): error CS0246: The type or namespace name 'scoped' could not be found (are you missing a using directive or an assembly reference?)
// readonly scoped record struct C();
Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "scoped").WithArguments("scoped").WithLocation(3, 10),
// (3,17): warning CS0168: The variable 'record' is declared but never used
// readonly scoped record struct C();
Diagnostic(ErrorCode.WRN_UnreferencedVar, "record").WithArguments("record").WithLocation(3, 17),
// (3,24): error CS1002: ; expected
// readonly scoped record struct C();
Diagnostic(ErrorCode.ERR_SemicolonExpected, "struct").WithLocation(3, 24),
// (3,32): error CS8652: The feature 'primary constructors' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.
// readonly scoped record struct C();
Diagnostic(ErrorCode.ERR_FeatureInPreview, "()").WithArguments("primary constructors").WithLocation(3, 32)
);
}
[Fact]
public void FieldTypeScope_01()
{
var source =
@"#pragma warning disable 169
ref struct R1 { }
ref struct R2
{
scoped R1 F1;
scoped ref int F3;
}";
var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10, targetFramework: TargetFramework.Net70);
comp.VerifyDiagnostics(
// (5,15): error CS0106: The modifier 'scoped' is not valid for this item
// scoped R1 F1;
Diagnostic(ErrorCode.ERR_BadMemberFlag, "F1").WithArguments("scoped").WithLocation(5, 15),
// (6,12): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater.
// scoped ref int F3;
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "ref int").WithArguments("ref fields", "11.0").WithLocation(6, 12),
// (6,20): error CS0106: The modifier 'scoped' is not valid for this item
// scoped ref int F3;
Diagnostic(ErrorCode.ERR_BadMemberFlag, "F3").WithArguments("scoped").WithLocation(6, 20));
comp = CreateCompilation(source, targetFramework: TargetFramework.Net70);
comp.VerifyDiagnostics(
// (5,15): error CS0106: The modifier 'scoped' is not valid for this item
// scoped R1 F1;
Diagnostic(ErrorCode.ERR_BadMemberFlag, "F1").WithArguments("scoped").WithLocation(5, 15),
// (6,20): error CS0106: The modifier 'scoped' is not valid for this item
// scoped ref int F3;
Diagnostic(ErrorCode.ERR_BadMemberFlag, "F3").WithArguments("scoped").WithLocation(6, 20));
}
[Fact]
public void FieldTypeScope_02()
{
var source =
@"#pragma warning disable 169
ref struct R1 { }
ref struct R2
{
scoped private R1 F1;
scoped private ref int F3;
}";
var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10, targetFramework: TargetFramework.Net70);
comp.VerifyDiagnostics(
// (5,12): error CS1585: Member modifier 'private' must precede the member type and name
// scoped private R1 F1;
Diagnostic(ErrorCode.ERR_BadModifierLocation, "private").WithArguments("private").WithLocation(5, 12),
// (6,12): error CS1585: Member modifier 'private' must precede the member type and name
// scoped private ref int F3;
Diagnostic(ErrorCode.ERR_BadModifierLocation, "private").WithArguments("private").WithLocation(6, 12),
// (6,20): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater.
// scoped private ref int F3;
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "ref int").WithArguments("ref fields", "11.0").WithLocation(6, 20));
comp = CreateCompilation(source, targetFramework: TargetFramework.Net70);
comp.VerifyDiagnostics(
// (5,12): error CS1585: Member modifier 'private' must precede the member type and name
// scoped private R1 F1;
Diagnostic(ErrorCode.ERR_BadModifierLocation, "private").WithArguments("private").WithLocation(5, 12),
// (6,12): error CS1585: Member modifier 'private' must precede the member type and name
// scoped private ref int F3;
Diagnostic(ErrorCode.ERR_BadModifierLocation, "private").WithArguments("private").WithLocation(6, 12));
}
[Theory]
[InlineData(LanguageVersion.CSharp10)]
[InlineData(LanguageVersion.CSharp11)]
public void PropertyTypeScope(LanguageVersion langVersion)
{
var source =
@"ref struct R1 { }
ref struct R2
{
scoped R1 P1 { get; }
scoped R1 P2 { get; init; }
scoped R1 P3 { set { } }
scoped ref int P5 => throw null;
}";
var comp = CreateCompilation(new[] { source, IsExternalInitTypeDefinition }, parseOptions: TestOptions.Regular.WithLanguageVersion(langVersion));
comp.VerifyDiagnostics(
// (4,15): error CS0106: The modifier 'scoped' is not valid for this item
// scoped R1 P1 { get; }
Diagnostic(ErrorCode.ERR_BadMemberFlag, "P1").WithArguments("scoped").WithLocation(4, 15),
// (5,15): error CS0106: The modifier 'scoped' is not valid for this item
// scoped R1 P2 { get; init; }
Diagnostic(ErrorCode.ERR_BadMemberFlag, "P2").WithArguments("scoped").WithLocation(5, 15),
// (6,15): error CS0106: The modifier 'scoped' is not valid for this item
// scoped R1 P3 { set { } }
Diagnostic(ErrorCode.ERR_BadMemberFlag, "P3").WithArguments("scoped").WithLocation(6, 15),
// (7,20): error CS0106: The modifier 'scoped' is not valid for this item
// scoped ref int P5 => throw null;
Diagnostic(ErrorCode.ERR_BadMemberFlag, "P5").WithArguments("scoped").WithLocation(7, 20));
verify(comp);
static void verify(CSharpCompilation comp)
{
verifyValueParameter(comp.GetMember<PropertySymbol>("R2.P2"), "R1 value", RefKind.None, ScopedKind.None);
verifyValueParameter(comp.GetMember<PropertySymbol>("R2.P3"), "R1 value", RefKind.None, ScopedKind.None);
}
static void verifyValueParameter(PropertySymbol property, string expectedDisplayString, RefKind expectedRefKind, ScopedKind expectedScope)
{
Assert.Equal(expectedRefKind, property.RefKind);
VerifyParameterSymbol(property.SetMethod.Parameters[0], expectedDisplayString, expectedRefKind, expectedScope);
}
}
[Fact]
public void SubstitutedParameter()
{
var source =
@"ref struct R<T> { }
class A<T>
{
public static void F(scoped R<T> x, scoped in T y) { }
}
class B : A<int>
{
}";
var comp = CreateCompilation(source);
comp.VerifyEmitDiagnostics();
var method = (MethodSymbol)comp.GetMember<NamedTypeSymbol>("B").BaseTypeNoUseSiteDiagnostics.GetMember("F");
VerifyParameterSymbol(method.Parameters[0], "scoped R<System.Int32> x", RefKind.None, ScopedKind.ScopedValue);
VerifyParameterSymbol(method.Parameters[1], "scoped in System.Int32 y", RefKind.In, ScopedKind.ScopedRef);
}
[Fact]
public void RetargetingParameter()
{
var sourceA =
@"public ref struct R { }
public class A
{
public static void F(scoped R x, scoped in int y) { }
}
";
var comp = CreateCompilation(sourceA, targetFramework: TargetFramework.Mscorlib40);
var refA = comp.ToMetadataReference();
var sourceB =
@"class B
{
static void Main()
{
A.F(default, 0);
}
}";
comp = CreateCompilation(sourceB, new[] { refA }, targetFramework: TargetFramework.Mscorlib45);
comp.VerifyEmitDiagnostics();
CompileAndVerify(comp);
var tree = comp.SyntaxTrees[0];
var model = comp.GetSemanticModel(tree);
var expr = tree.GetRoot().DescendantNodes().OfType<InvocationExpressionSyntax>().Single().Expression;
var method = model.GetSymbolInfo(expr).Symbol.GetSymbol<RetargetingMethodSymbol>();
VerifyParameterSymbol(method.Parameters[0], "scoped R x", RefKind.None, ScopedKind.ScopedValue);
VerifyParameterSymbol(method.Parameters[1], "scoped in System.Int32 y", RefKind.In, ScopedKind.ScopedRef);
}
private static readonly SymbolDisplayFormat displayFormatWithScoped = SymbolDisplayFormat.TestFormat.
AddParameterOptions(SymbolDisplayParameterOptions.IncludeModifiers).
AddLocalOptions(SymbolDisplayLocalOptions.IncludeModifiers);
private static void VerifyParameterSymbol(ParameterSymbol parameter, string expectedDisplayString, RefKind expectedRefKind, ScopedKind expectedScope, bool expectedHasUnscopedRefAttribute = false)
{
Assert.Equal(expectedDisplayString, parameter.ToDisplayString(displayFormatWithScoped));
Assert.Equal(expectedRefKind, parameter.RefKind);
Assert.Equal(expectedScope, parameter.EffectiveScope);
Assert.Equal(expectedHasUnscopedRefAttribute, parameter.HasUnscopedRefAttribute);
var attribute = parameter.GetAttributes().FirstOrDefault(a => a.GetTargetAttributeSignatureIndex(parameter, AttributeDescription.ScopedRefAttribute) != -1);
Assert.Null(attribute);
VerifyParameterSymbol(parameter.GetPublicSymbol(), expectedDisplayString, expectedRefKind, expectedScope);
}
private static void VerifyParameterSymbol(IParameterSymbol parameter, string expectedDisplayString, RefKind expectedRefKind, ScopedKind expectedScope)
{
Assert.Equal(expectedRefKind, parameter.RefKind);
Assert.Equal(expectedScope, parameter.ScopedKind);
Assert.Equal(expectedDisplayString, parameter.ToDisplayString(displayFormatWithScoped));
}
[Fact]
public void LocalScope_01()
{
var source =
@"#pragma warning disable 219
ref struct R { }
class Program
{
static void F(ref R r)
{
scoped R r1 = default;
scoped ref R r2 = ref r;
scoped ref readonly R r5 = ref r;
scoped var r11 = (R)default;
scoped ref var r21 = ref r;
scoped ref readonly var r51 = ref r;
}
}";
var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10);
comp.VerifyEmitDiagnostics(
// (7,9): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater.
// scoped R r1 = default;
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "scoped").WithArguments("ref fields", "11.0").WithLocation(7, 9),
// (8,9): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater.
// scoped ref R r2 = ref r;
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "scoped").WithArguments("ref fields", "11.0").WithLocation(8, 9),
// (9,9): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater.
// scoped ref readonly R r5 = ref r;
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "scoped").WithArguments("ref fields", "11.0").WithLocation(9, 9),
// (10,9): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater.
// scoped var r11 = (R)default;
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "scoped").WithArguments("ref fields", "11.0").WithLocation(10, 9),
// (11,9): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater.
// scoped ref var r21 = ref r;
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "scoped").WithArguments("ref fields", "11.0").WithLocation(11, 9),
// (12,9): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater.
// scoped ref readonly var r51 = ref r;
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "scoped").WithArguments("ref fields", "11.0").WithLocation(12, 9)
);
verify(comp);
comp = CreateCompilation(source);
comp.VerifyEmitDiagnostics();
verify(comp);
static void verify(CSharpCompilation comp)
{
var tree = comp.SyntaxTrees[0];
var model = comp.GetSemanticModel(tree);
var decls = tree.GetRoot().DescendantNodes().OfType<VariableDeclaratorSyntax>().ToArray();
var locals = decls.Select(d => model.GetDeclaredSymbol(d).GetSymbol<LocalSymbol>()).ToArray();
VerifyLocalSymbol(locals[0], "scoped R r1", RefKind.None, ScopedKind.ScopedValue);
VerifyLocalSymbol(locals[1], "scoped ref R r2", RefKind.Ref, ScopedKind.ScopedRef);
VerifyLocalSymbol(locals[2], "scoped ref readonly R r5", RefKind.RefReadOnly, ScopedKind.ScopedRef);
VerifyLocalSymbol(locals[3], "scoped R r11", RefKind.None, ScopedKind.ScopedValue);
VerifyLocalSymbol(locals[4], "scoped ref R r21", RefKind.Ref, ScopedKind.ScopedRef);
VerifyLocalSymbol(locals[5], "scoped ref readonly R r51", RefKind.RefReadOnly, ScopedKind.ScopedRef);
foreach (var decl in decls)
{
var type = ((VariableDeclarationSyntax)decl.Parent).Type;
Assert.True(SyntaxFacts.IsInTypeOnlyContext(type));
Assert.True(SyntaxFacts.IsInTypeOnlyContext(type.SkipScoped(out _)));
Assert.True(SyntaxFacts.IsInTypeOnlyContext(type.SkipScoped(out _).SkipRef()));
Assert.Null(model.GetSymbolInfo(type).Symbol);
Assert.Null(model.GetTypeInfo(type).Type);
type = type.SkipScoped(out _);
if (type is RefTypeSyntax refType)
{
Assert.Null(model.GetSymbolInfo(type).Symbol);
Assert.Null(model.GetTypeInfo(type).Type);
type = refType.Type;
}
Assert.Equal("R", model.GetSymbolInfo(type).Symbol.ToTestDisplayString());
Assert.Equal("R", model.GetTypeInfo(type).Type.ToTestDisplayString());
}
}
}
[Fact]
public void LocalScope_01_Script()
{
var source =
@"#pragma warning disable 219
scoped R r1 = default;
scoped var r11 = (R)default;
ref struct R { }
";
var comp = CreateCompilation(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script);
comp.VerifyEmitDiagnostics(
// (2,1): error CS8345: Field or auto-implemented property cannot be of type 'R' unless it is an instance member of a ref struct.
// scoped R r1 = default;
Diagnostic(ErrorCode.ERR_FieldAutoPropCantBeByRefLike, "scoped R").WithArguments("R").WithLocation(2, 1),
// (2,10): error CS0106: The modifier 'scoped' is not valid for this item
// scoped R r1 = default;
Diagnostic(ErrorCode.ERR_BadMemberFlag, "r1").WithArguments("scoped").WithLocation(2, 10),
// (3,1): error CS8345: Field or auto-implemented property cannot be of type 'R' unless it is an instance member of a ref struct.
// scoped var r11 = (R)default;
Diagnostic(ErrorCode.ERR_FieldAutoPropCantBeByRefLike, "scoped var").WithArguments("R").WithLocation(3, 1),
// (3,12): error CS0106: The modifier 'scoped' is not valid for this item
// scoped var r11 = (R)default;
Diagnostic(ErrorCode.ERR_BadMemberFlag, "r11").WithArguments("scoped").WithLocation(3, 12)
);
verify(comp);
static void verify(CSharpCompilation comp)
{
var tree = comp.SyntaxTrees[0];
var model = comp.GetSemanticModel(tree);
var decls = tree.GetRoot().DescendantNodes().OfType<VariableDeclaratorSyntax>().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("Script.R", f.Type.ToTestDisplayString());
var type = ((VariableDeclarationSyntax)decl.Parent).Type;
Assert.Null(model.GetSymbolInfo(type).Symbol);
Assert.Null(model.GetTypeInfo(type).Type);
type = type.SkipScoped(out _);
if (type is RefTypeSyntax refType)
{
Assert.Null(model.GetSymbolInfo(type).Symbol);
Assert.Null(model.GetTypeInfo(type).Type);
type = refType.Type;
}
Assert.Equal("Script.R", model.GetSymbolInfo(type).Symbol.ToTestDisplayString());
Assert.Equal("Script.R", model.GetTypeInfo(type).Type.ToTestDisplayString());
}
}
}
[Fact]
public void LocalScope_01_For()
{
var source =
@"#pragma warning disable 219
ref struct R { }
class Program
{
static void F(ref R r)
{
for (scoped R r1 = default;;) break;
for (scoped ref R r2 = ref r;;) break;
for (scoped ref readonly R r5 = ref r;;) break;
}
}";
var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10);
comp.VerifyEmitDiagnostics(
// (7,14): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater.
// for (scoped R r1 = default;;) break;
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "scoped").WithArguments("ref fields", "11.0").WithLocation(7, 14),
// (8,14): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater.
// for (scoped ref R r2 = ref r;;) break;
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "scoped").WithArguments("ref fields", "11.0").WithLocation(8, 14),
// (9,14): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater.
// for (scoped ref readonly R r5 = ref r;;) break;
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "scoped").WithArguments("ref fields", "11.0").WithLocation(9, 14));
verify(comp);
comp = CreateCompilation(source);
comp.VerifyEmitDiagnostics();
verify(comp);
static void verify(CSharpCompilation comp)
{
var tree = comp.SyntaxTrees[0];
var model = comp.GetSemanticModel(tree);
var decls = tree.GetRoot().DescendantNodes().OfType<VariableDeclaratorSyntax>().ToArray();
var locals = decls.Select(d => model.GetDeclaredSymbol(d).GetSymbol<LocalSymbol>()).ToArray();
VerifyLocalSymbol(locals[0], "scoped R r1", RefKind.None, ScopedKind.ScopedValue);
VerifyLocalSymbol(locals[1], "scoped ref R r2", RefKind.Ref, ScopedKind.ScopedRef);
VerifyLocalSymbol(locals[2], "scoped ref readonly R r5", RefKind.RefReadOnly, ScopedKind.ScopedRef);
foreach (var decl in decls)
{
var type = ((VariableDeclarationSyntax)decl.Parent).Type;
Assert.True(SyntaxFacts.IsInTypeOnlyContext(type));
Assert.True(SyntaxFacts.IsInTypeOnlyContext(type.SkipScoped(out _)));
Assert.True(SyntaxFacts.IsInTypeOnlyContext(type.SkipScoped(out _).SkipRef()));
Assert.Null(model.GetSymbolInfo(type).Symbol);
Assert.Null(model.GetTypeInfo(type).Type);
type = type.SkipScoped(out _);
if (type is RefTypeSyntax refType)
{
Assert.Null(model.GetSymbolInfo(type).Symbol);
Assert.Null(model.GetTypeInfo(type).Type);
type = refType.Type;
}
Assert.Equal("R", model.GetSymbolInfo(type).Symbol.ToTestDisplayString());
Assert.Equal("R", model.GetTypeInfo(type).Type.ToTestDisplayString());
}
}
}
[Fact]
public void LocalScope_01_Deconstruction()
{
var source =
@"#pragma warning disable 219
ref struct R { }
class Program
{
static void F(RR r)
{
(scoped R r1, var a) = r;
(scoped ref R r2, var b) = r;
(scoped ref readonly R r5, var c) = r;
(scoped R _, var d) = r;
(scoped var _, var e) = r;
(scoped ref R _, var f) = r;
(scoped ref var _, var g) = r;
(scoped ref readonly R _, var h) = r;
(scoped ref readonly var _, var i) = r;
(scoped var r11, var j) = r;
(scoped ref var r21, var k) = r;
(scoped ref readonly var r51, var l) = r;
}
}
class RR
{
public void Deconstruct(out R x, out int y) => throw null;
}
";
var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10);
comp.VerifyEmitDiagnostics(
// (7,10): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater.
// (scoped R r1, var a) = r;
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "scoped").WithArguments("ref fields", "11.0").WithLocation(7, 10),
// (8,10): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater.
// (scoped ref R r2, var b) = r;
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "scoped").WithArguments("ref fields", "11.0").WithLocation(8, 10),
// (8,17): error CS9072: A deconstruction variable cannot be declared as a ref local
// (scoped ref R r2, var b) = r;
Diagnostic(ErrorCode.ERR_DeconstructVariableCannotBeByRef, "ref").WithLocation(8, 17),
// (9,10): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater.
// (scoped ref readonly R r5, var c) = r;
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "scoped").WithArguments("ref fields", "11.0").WithLocation(9, 10),
// (9,17): error CS9072: A deconstruction variable cannot be declared as a ref local
// (scoped ref readonly R r5, var c) = r;
Diagnostic(ErrorCode.ERR_DeconstructVariableCannotBeByRef, "ref").WithLocation(9, 17),
// (10,10): error CS9061: The 'scoped' modifier cannot be used with discard.
// (scoped R _, var d) = r;
Diagnostic(ErrorCode.ERR_ScopedDiscard, "scoped").WithLocation(10, 10),
// (11,10): error CS9061: The 'scoped' modifier cannot be used with discard.
// (scoped var _, var e) = r;
Diagnostic(ErrorCode.ERR_ScopedDiscard, "scoped").WithLocation(11, 10),
// (12,10): error CS9061: The 'scoped' modifier cannot be used with discard.
// (scoped ref R _, var f) = r;
Diagnostic(ErrorCode.ERR_ScopedDiscard, "scoped").WithLocation(12, 10),
// (12,17): error CS9072: A deconstruction variable cannot be declared as a ref local
// (scoped ref R _, var f) = r;
Diagnostic(ErrorCode.ERR_DeconstructVariableCannotBeByRef, "ref").WithLocation(12, 17),
// (13,10): error CS9061: The 'scoped' modifier cannot be used with discard.
// (scoped ref var _, var g) = r;
Diagnostic(ErrorCode.ERR_ScopedDiscard, "scoped").WithLocation(13, 10),
// (13,17): error CS9072: A deconstruction variable cannot be declared as a ref local
// (scoped ref var _, var g) = r;
Diagnostic(ErrorCode.ERR_DeconstructVariableCannotBeByRef, "ref").WithLocation(13, 17),
// (14,10): error CS9061: The 'scoped' modifier cannot be used with discard.
// (scoped ref readonly R _, var h) = r;
Diagnostic(ErrorCode.ERR_ScopedDiscard, "scoped").WithLocation(14, 10),
// (14,17): error CS9072: A deconstruction variable cannot be declared as a ref local
// (scoped ref readonly R _, var h) = r;
Diagnostic(ErrorCode.ERR_DeconstructVariableCannotBeByRef, "ref").WithLocation(14, 17),
// (15,10): error CS9061: The 'scoped' modifier cannot be used with discard.
// (scoped ref readonly var _, var i) = r;
Diagnostic(ErrorCode.ERR_ScopedDiscard, "scoped").WithLocation(15, 10),
// (15,17): error CS9072: A deconstruction variable cannot be declared as a ref local
// (scoped ref readonly var _, var i) = r;
Diagnostic(ErrorCode.ERR_DeconstructVariableCannotBeByRef, "ref").WithLocation(15, 17),
// (16,10): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater.
// (scoped var r11, var j) = r;
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "scoped").WithArguments("ref fields", "11.0").WithLocation(16, 10),
// (17,10): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater.
// (scoped ref var r21, var k) = r;
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "scoped").WithArguments("ref fields", "11.0").WithLocation(17, 10),
// (17,17): error CS9072: A deconstruction variable cannot be declared as a ref local
// (scoped ref var r21, var k) = r;
Diagnostic(ErrorCode.ERR_DeconstructVariableCannotBeByRef, "ref").WithLocation(17, 17),
// (18,10): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater.
// (scoped ref readonly var r51, var l) = r;
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "scoped").WithArguments("ref fields", "11.0").WithLocation(18, 10),
// (18,17): error CS9072: A deconstruction variable cannot be declared as a ref local
// (scoped ref readonly var r51, var l) = r;
Diagnostic(ErrorCode.ERR_DeconstructVariableCannotBeByRef, "ref").WithLocation(18, 17)
);
verify(comp);
comp = CreateCompilation(source);
comp.VerifyEmitDiagnostics(
// (8,17): error CS9072: A deconstruction variable cannot be declared as a ref local
// (scoped ref R r2, var b) = r;
Diagnostic(ErrorCode.ERR_DeconstructVariableCannotBeByRef, "ref").WithLocation(8, 17),
// (9,17): error CS9072: A deconstruction variable cannot be declared as a ref local
// (scoped ref readonly R r5, var c) = r;
Diagnostic(ErrorCode.ERR_DeconstructVariableCannotBeByRef, "ref").WithLocation(9, 17),
// (10,10): error CS9061: The 'scoped' modifier cannot be used with discard.
// (scoped R _, var d) = r;
Diagnostic(ErrorCode.ERR_ScopedDiscard, "scoped").WithLocation(10, 10),
// (11,10): error CS9061: The 'scoped' modifier cannot be used with discard.
// (scoped var _, var e) = r;
Diagnostic(ErrorCode.ERR_ScopedDiscard, "scoped").WithLocation(11, 10),
// (12,10): error CS9061: The 'scoped' modifier cannot be used with discard.
// (scoped ref R _, var f) = r;
Diagnostic(ErrorCode.ERR_ScopedDiscard, "scoped").WithLocation(12, 10),
// (12,17): error CS9072: A deconstruction variable cannot be declared as a ref local
// (scoped ref R _, var f) = r;
Diagnostic(ErrorCode.ERR_DeconstructVariableCannotBeByRef, "ref").WithLocation(12, 17),
// (13,10): error CS9061: The 'scoped' modifier cannot be used with discard.
// (scoped ref var _, var g) = r;
Diagnostic(ErrorCode.ERR_ScopedDiscard, "scoped").WithLocation(13, 10),
// (13,17): error CS9072: A deconstruction variable cannot be declared as a ref local
// (scoped ref var _, var g) = r;
Diagnostic(ErrorCode.ERR_DeconstructVariableCannotBeByRef, "ref").WithLocation(13, 17),
// (14,10): error CS9061: The 'scoped' modifier cannot be used with discard.
// (scoped ref readonly R _, var h) = r;
Diagnostic(ErrorCode.ERR_ScopedDiscard, "scoped").WithLocation(14, 10),
// (14,17): error CS9072: A deconstruction variable cannot be declared as a ref local
// (scoped ref readonly R _, var h) = r;
Diagnostic(ErrorCode.ERR_DeconstructVariableCannotBeByRef, "ref").WithLocation(14, 17),
// (15,10): error CS9061: The 'scoped' modifier cannot be used with discard.
// (scoped ref readonly var _, var i) = r;
Diagnostic(ErrorCode.ERR_ScopedDiscard, "scoped").WithLocation(15, 10),
// (15,17): error CS9072: A deconstruction variable cannot be declared as a ref local
// (scoped ref readonly var _, var i) = r;
Diagnostic(ErrorCode.ERR_DeconstructVariableCannotBeByRef, "ref").WithLocation(15, 17),
// (17,17): error CS9072: A deconstruction variable cannot be declared as a ref local
// (scoped ref var r21, var k) = r;
Diagnostic(ErrorCode.ERR_DeconstructVariableCannotBeByRef, "ref").WithLocation(17, 17),
// (18,17): error CS9072: A deconstruction variable cannot be declared as a ref local
// (scoped ref readonly var r51, var l) = r;
Diagnostic(ErrorCode.ERR_DeconstructVariableCannotBeByRef, "ref").WithLocation(18, 17)
);
verify(comp);
static void verify(CSharpCompilation comp)
{
var tree = comp.SyntaxTrees[0];
var model = comp.GetSemanticModel(tree);
var decls = tree.GetRoot().DescendantNodes().OfType<DeclarationExpressionSyntax>().
Where(d => d.Type is ScopedTypeSyntax && d.Designation is SingleVariableDesignationSyntax).
Select(d => d.Designation).ToArray();
var locals = decls.Select(d => model.GetDeclaredSymbol(d).GetSymbol<LocalSymbol>()).ToArray();
Assert.Equal(6, locals.Length);
VerifyLocalSymbol(locals[0], "scoped R r1", RefKind.None, ScopedKind.ScopedValue);
VerifyLocalSymbol(locals[1], "scoped R r2", RefKind.None, ScopedKind.ScopedValue);
VerifyLocalSymbol(locals[2], "scoped R r5", RefKind.None, ScopedKind.ScopedValue);
VerifyLocalSymbol(locals[3], "scoped R r11", RefKind.None, ScopedKind.ScopedValue);
VerifyLocalSymbol(locals[4], "scoped R r21", RefKind.None, ScopedKind.ScopedValue);
VerifyLocalSymbol(locals[5], "scoped R r51", RefKind.None, ScopedKind.ScopedValue);
foreach (var decl in decls)
{
var type = ((DeclarationExpressionSyntax)decl.Parent).Type;
Assert.True(SyntaxFacts.IsInTypeOnlyContext(type));
Assert.True(SyntaxFacts.IsInTypeOnlyContext(type.SkipScoped(out _)));
Assert.True(SyntaxFacts.IsInTypeOnlyContext(type.SkipScoped(out _).SkipRef()));
Assert.Null(model.GetSymbolInfo(type).Symbol);
Assert.Null(model.GetTypeInfo(type).Type);
type = type.SkipScoped(out _);
if (type is RefTypeSyntax refType)
{
Assert.Null(model.GetSymbolInfo(type).Symbol);
Assert.Null(model.GetTypeInfo(type).Type);
type = refType.Type;
}
Assert.Equal("R", model.GetSymbolInfo(type).Symbol.ToTestDisplayString());
Assert.Equal("R", model.GetTypeInfo(type).Type.ToTestDisplayString());
}
var discard = tree.GetRoot().DescendantNodes().OfType<DiscardDesignationSyntax>().ToArray();
Assert.Equal(6, discard.Length);
foreach (var decl in discard)
{
Assert.Null(model.GetDeclaredSymbol(decl));
Assert.Null(model.GetSymbolInfo(decl).Symbol);
Assert.Null(model.GetTypeInfo(decl).Type);
var type = ((DeclarationExpressionSyntax)decl.Parent).Type;
Assert.True(SyntaxFacts.IsInTypeOnlyContext(type));
Assert.True(SyntaxFacts.IsInTypeOnlyContext(type.SkipScoped(out _)));
Assert.True(SyntaxFacts.IsInTypeOnlyContext(type.SkipScoped(out _).SkipRef()));
Assert.Null(model.GetSymbolInfo(type).Symbol);
Assert.Null(model.GetTypeInfo(type).Type);
type = type.SkipScoped(out _);
if (type is RefTypeSyntax refType)
{
Assert.Null(model.GetSymbolInfo(type).Symbol);
Assert.Null(model.GetTypeInfo(type).Type);
type = refType.Type;
}
Assert.Equal("R", model.GetSymbolInfo(type).Symbol.ToTestDisplayString());
Assert.Equal("R", model.GetTypeInfo(type).Type.ToTestDisplayString());
}
}
}
[Fact]
public void LocalScope_01_Deconstruction_Script()
{
var source =
@"#pragma warning disable 219
RR r = new RR();
(scoped R r1, var a) = r;
(scoped ref R r2, var b) = r;
(scoped ref readonly R r5, var c) = r;
(scoped R _, var d) = r;
(scoped var _, var e) = r;
(scoped ref R _, var f) = r;
(scoped ref var _, var g) = r;
(scoped ref readonly R _, var h) = r;
(scoped ref readonly var _, var i) = r;
(scoped var r11, var j) = r;
(scoped ref var r21, var k) = r;
(scoped ref readonly var r51, var l) = r;
ref struct R { }
class RR
{
public void Deconstruct(out R x, out int y) => throw null;
}
";
var comp = CreateCompilation(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script);
comp.VerifyEmitDiagnostics(
// (3,2): error CS8345: Field or auto-implemented property cannot be of type 'R' unless it is an instance member of a ref struct.
// (scoped R r1, var a) = r;
Diagnostic(ErrorCode.ERR_FieldAutoPropCantBeByRefLike, "scoped R").WithArguments("R").WithLocation(3, 2),
// (3,2): error CS1073: Unexpected token 'scoped'
// (scoped R r1, var a) = r;
Diagnostic(ErrorCode.ERR_UnexpectedToken, "scoped").WithArguments("scoped").WithLocation(3, 2),
// (4,2): error CS8345: Field or auto-implemented property cannot be of type 'R' unless it is an instance member of a ref struct.
// (scoped ref R r2, var b) = r;
Diagnostic(ErrorCode.ERR_FieldAutoPropCantBeByRefLike, "scoped ref R").WithArguments("R").WithLocation(4, 2),
// (4,2): error CS1073: Unexpected token 'scoped'
// (scoped ref R r2, var b) = r;
Diagnostic(ErrorCode.ERR_UnexpectedToken, "scoped").WithArguments("scoped").WithLocation(4, 2),
// (4,9): error CS1073: Unexpected token 'ref'
// (scoped ref R r2, var b) = r;
Diagnostic(ErrorCode.ERR_UnexpectedToken, "ref").WithArguments("ref").WithLocation(4, 9),
// (5,2): error CS8345: Field or auto-implemented property cannot be of type 'R' unless it is an instance member of a ref struct.
// (scoped ref readonly R r5, var c) = r;
Diagnostic(ErrorCode.ERR_FieldAutoPropCantBeByRefLike, "scoped ref readonly R").WithArguments("R").WithLocation(5, 2),
// (5,2): error CS1073: Unexpected token 'scoped'
// (scoped ref readonly R r5, var c) = r;
Diagnostic(ErrorCode.ERR_UnexpectedToken, "scoped").WithArguments("scoped").WithLocation(5, 2),
// (5,9): error CS1073: Unexpected token 'ref'
// (scoped ref readonly R r5, var c) = r;
Diagnostic(ErrorCode.ERR_UnexpectedToken, "ref").WithArguments("ref").WithLocation(5, 9),
// (6,2): error CS9061: The 'scoped' modifier cannot be used with discard.
// (scoped R _, var d) = r;
Diagnostic(ErrorCode.ERR_ScopedDiscard, "scoped").WithLocation(6, 2),
// (7,2): error CS9061: The 'scoped' modifier cannot be used with discard.
// (scoped var _, var e) = r;
Diagnostic(ErrorCode.ERR_ScopedDiscard, "scoped").WithLocation(7, 2),
// (8,2): error CS9061: The 'scoped' modifier cannot be used with discard.
// (scoped ref R _, var f) = r;
Diagnostic(ErrorCode.ERR_ScopedDiscard, "scoped").WithLocation(8, 2),
// (8,9): error CS9072: A deconstruction variable cannot be declared as a ref local
// (scoped ref R _, var f) = r;
Diagnostic(ErrorCode.ERR_DeconstructVariableCannotBeByRef, "ref").WithLocation(8, 9),
// (9,2): error CS9061: The 'scoped' modifier cannot be used with discard.
// (scoped ref var _, var g) = r;
Diagnostic(ErrorCode.ERR_ScopedDiscard, "scoped").WithLocation(9, 2),
// (9,9): error CS9072: A deconstruction variable cannot be declared as a ref local
// (scoped ref var _, var g) = r;
Diagnostic(ErrorCode.ERR_DeconstructVariableCannotBeByRef, "ref").WithLocation(9, 9),
// (10,2): error CS9061: The 'scoped' modifier cannot be used with discard.
// (scoped ref readonly R _, var h) = r;
Diagnostic(ErrorCode.ERR_ScopedDiscard, "scoped").WithLocation(10, 2),
// (10,9): error CS9072: A deconstruction variable cannot be declared as a ref local
// (scoped ref readonly R _, var h) = r;
Diagnostic(ErrorCode.ERR_DeconstructVariableCannotBeByRef, "ref").WithLocation(10, 9),
// (11,2): error CS9061: The 'scoped' modifier cannot be used with discard.
// (scoped ref readonly var _, var i) = r;
Diagnostic(ErrorCode.ERR_ScopedDiscard, "scoped").WithLocation(11, 2),
// (11,9): error CS9072: A deconstruction variable cannot be declared as a ref local
// (scoped ref readonly var _, var i) = r;
Diagnostic(ErrorCode.ERR_DeconstructVariableCannotBeByRef, "ref").WithLocation(11, 9),
// (12,2): error CS8345: Field or auto-implemented property cannot be of type 'R' unless it is an instance member of a ref struct.
// (scoped var r11, var j) = r;
Diagnostic(ErrorCode.ERR_FieldAutoPropCantBeByRefLike, "scoped var").WithArguments("R").WithLocation(12, 2),
// (12,2): error CS1073: Unexpected token 'scoped'
// (scoped var r11, var j) = r;
Diagnostic(ErrorCode.ERR_UnexpectedToken, "scoped").WithArguments("scoped").WithLocation(12, 2),
// (13,2): error CS8345: Field or auto-implemented property cannot be of type 'R' unless it is an instance member of a ref struct.
// (scoped ref var r21, var k) = r;
Diagnostic(ErrorCode.ERR_FieldAutoPropCantBeByRefLike, "scoped ref var").WithArguments("R").WithLocation(13, 2),
// (13,2): error CS1073: Unexpected token 'scoped'
// (scoped ref var r21, var k) = r;
Diagnostic(ErrorCode.ERR_UnexpectedToken, "scoped").WithArguments("scoped").WithLocation(13, 2),
// (13,9): error CS1073: Unexpected token 'ref'
// (scoped ref var r21, var k) = r;
Diagnostic(ErrorCode.ERR_UnexpectedToken, "ref").WithArguments("ref").WithLocation(13, 9),
// (14,2): error CS8345: Field or auto-implemented property cannot be of type 'R' unless it is an instance member of a ref struct.
// (scoped ref readonly var r51, var l) = r;
Diagnostic(ErrorCode.ERR_FieldAutoPropCantBeByRefLike, "scoped ref readonly var").WithArguments("R").WithLocation(14, 2),
// (14,2): error CS1073: Unexpected token 'scoped'
// (scoped ref readonly var r51, var l) = r;
Diagnostic(ErrorCode.ERR_UnexpectedToken, "scoped").WithArguments("scoped").WithLocation(14, 2),
// (14,9): error CS1073: Unexpected token 'ref'
// (scoped ref readonly var r51, var l) = r;
Diagnostic(ErrorCode.ERR_UnexpectedToken, "ref").WithArguments("ref").WithLocation(14, 9)
);
verify(comp);
static void verify(CSharpCompilation comp)
{
var tree = comp.SyntaxTrees[0];
var model = comp.GetSemanticModel(tree);
var decls = tree.GetRoot().DescendantNodes().OfType<DeclarationExpressionSyntax>().
Where(d => d.Type is ScopedTypeSyntax && d.Designation is SingleVariableDesignationSyntax).
Select(d => d.Designation).ToArray();
Assert.Equal(6, decls.Length);
foreach (var decl in decls)
{
var f = model.GetDeclaredSymbol(decl).GetSymbol<FieldSymbol>();
Assert.Equal(RefKind.None, f.RefKind);
Assert.Equal("Script.R", f.Type.ToTestDisplayString());
var type = ((DeclarationExpressionSyntax)decl.Parent).Type;
Assert.Null(model.GetSymbolInfo(type).Symbol);
Assert.Null(model.GetTypeInfo(type).Type);
type = type.SkipScoped(out _);
if (type is RefTypeSyntax refType)
{
Assert.Null(model.GetSymbolInfo(type).Symbol);
Assert.Null(model.GetTypeInfo(type).Type);
type = refType.Type;
}
Assert.Equal("Script.R", model.GetSymbolInfo(type).Symbol.ToTestDisplayString());
Assert.Equal("Script.R", model.GetTypeInfo(type).Type.ToTestDisplayString());
}
var discard = tree.GetRoot().DescendantNodes().OfType<DiscardDesignationSyntax>().ToArray();
Assert.Equal(6, discard.Length);
foreach (var decl in discard)
{
Assert.Null(model.GetDeclaredSymbol(decl));
Assert.Null(model.GetSymbolInfo(decl).Symbol);
Assert.Null(model.GetTypeInfo(decl).Type);
var type = ((DeclarationExpressionSyntax)decl.Parent).Type;
Assert.Null(model.GetSymbolInfo(type).Symbol);
Assert.Null(model.GetTypeInfo(type).Type);
type = type.SkipScoped(out _);
if (type is RefTypeSyntax refType)
{
Assert.Null(model.GetSymbolInfo(type).Symbol);
Assert.Null(model.GetTypeInfo(type).Type);
type = refType.Type;
}
Assert.Equal("Script.R", model.GetSymbolInfo(type).Symbol.ToTestDisplayString());
Assert.Equal("Script.R", model.GetTypeInfo(type).Type.ToTestDisplayString());
}
}
}
[Fact]
public void LocalScope_01_OutVar()
{
var source =
@"#pragma warning disable 219
ref struct R { }
class Program
{
static void F(ref R r)
{
M1(out scoped R r1);
M1(out scoped ref R r2);
M1(out scoped ref readonly R r5);
M1(out scoped R _);
M1(out scoped var _);
M1(out scoped ref R _);
M1(out scoped ref var _);
M1(out scoped ref readonly R _);
M1(out scoped ref readonly var _);
M1(out scoped var r11);
M1(out scoped ref var r21);
M1(out scoped ref readonly var r51);
M1(out scoped _);
M1(out scoped scoped _);
}
static void M1(out R r) => throw null;
}";
var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10);
comp.VerifyEmitDiagnostics(
// (7,16): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater.
// M1(out scoped R r1);
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "scoped").WithArguments("ref fields", "11.0").WithLocation(7, 16),
// (8,16): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater.
// M1(out scoped ref R r2);
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "scoped").WithArguments("ref fields", "11.0").WithLocation(8, 16),
// (8,23): error CS8388: An out variable cannot be declared as a ref local
// M1(out scoped ref R r2);
Diagnostic(ErrorCode.ERR_OutVariableCannotBeByRef, "ref R").WithLocation(8, 23),
// (9,16): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater.
// M1(out scoped ref readonly R r5);
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "scoped").WithArguments("ref fields", "11.0").WithLocation(9, 16),
// (9,23): error CS8388: An out variable cannot be declared as a ref local
// M1(out scoped ref readonly R r5);
Diagnostic(ErrorCode.ERR_OutVariableCannotBeByRef, "ref readonly R").WithLocation(9, 23),
// (10,16): error CS9061: The 'scoped' modifier cannot be used with discard.
// M1(out scoped R _);
Diagnostic(ErrorCode.ERR_ScopedDiscard, "scoped").WithLocation(10, 16),
// (11,16): error CS9061: The 'scoped' modifier cannot be used with discard.
// M1(out scoped var _);
Diagnostic(ErrorCode.ERR_ScopedDiscard, "scoped").WithLocation(11, 16),
// (12,16): error CS9061: The 'scoped' modifier cannot be used with discard.
// M1(out scoped ref R _);
Diagnostic(ErrorCode.ERR_ScopedDiscard, "scoped").WithLocation(12, 16),
// (12,23): error CS8388: An out variable cannot be declared as a ref local
// M1(out scoped ref R _);
Diagnostic(ErrorCode.ERR_OutVariableCannotBeByRef, "ref R").WithLocation(12, 23),
// (13,16): error CS9061: The 'scoped' modifier cannot be used with discard.
// M1(out scoped ref var _);
Diagnostic(ErrorCode.ERR_ScopedDiscard, "scoped").WithLocation(13, 16),
// (13,23): error CS8388: An out variable cannot be declared as a ref local
// M1(out scoped ref var _);
Diagnostic(ErrorCode.ERR_OutVariableCannotBeByRef, "ref var").WithLocation(13, 23),
// (14,16): error CS9061: The 'scoped' modifier cannot be used with discard.
// M1(out scoped ref readonly R _);
Diagnostic(ErrorCode.ERR_ScopedDiscard, "scoped").WithLocation(14, 16),
// (14,23): error CS8388: An out variable cannot be declared as a ref local
// M1(out scoped ref readonly R _);
Diagnostic(ErrorCode.ERR_OutVariableCannotBeByRef, "ref readonly R").WithLocation(14, 23),
// (15,16): error CS9061: The 'scoped' modifier cannot be used with discard.
// M1(out scoped ref readonly var _);
Diagnostic(ErrorCode.ERR_ScopedDiscard, "scoped").WithLocation(15, 16),
// (15,23): error CS8388: An out variable cannot be declared as a ref local
// M1(out scoped ref readonly var _);
Diagnostic(ErrorCode.ERR_OutVariableCannotBeByRef, "ref readonly var").WithLocation(15, 23),
// (16,16): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater.
// M1(out scoped var r11);
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "scoped").WithArguments("ref fields", "11.0").WithLocation(16, 16),
// (17,16): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater.
// M1(out scoped ref var r21);
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "scoped").WithArguments("ref fields", "11.0").WithLocation(17, 16),
// (17,23): error CS8388: An out variable cannot be declared as a ref local
// M1(out scoped ref var r21);
Diagnostic(ErrorCode.ERR_OutVariableCannotBeByRef, "ref var").WithLocation(17, 23),
// (18,16): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater.
// M1(out scoped ref readonly var r51);
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "scoped").WithArguments("ref fields", "11.0").WithLocation(18, 16),
// (18,23): error CS8388: An out variable cannot be declared as a ref local
// M1(out scoped ref readonly var r51);
Diagnostic(ErrorCode.ERR_OutVariableCannotBeByRef, "ref readonly var").WithLocation(18, 23),
// (20,16): error CS0246: The type or namespace name 'scoped' could not be found (are you missing a using directive or an assembly reference?)
// M1(out scoped _);
Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "scoped").WithArguments("scoped").WithLocation(20, 16),
// (21,16): error CS9061: The 'scoped' modifier cannot be used with discard.
// M1(out scoped scoped _);
Diagnostic(ErrorCode.ERR_ScopedDiscard, "scoped").WithLocation(21, 16),
// (21,23): error CS0246: The type or namespace name 'scoped' could not be found (are you missing a using directive or an assembly reference?)
// M1(out scoped scoped _);
Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "scoped").WithArguments("scoped").WithLocation(21, 23)
);
verify(comp);
comp = CreateCompilation(source);
comp.VerifyEmitDiagnostics(
// (8,23): error CS8388: An out variable cannot be declared as a ref local
// M1(out scoped ref R r2);
Diagnostic(ErrorCode.ERR_OutVariableCannotBeByRef, "ref R").WithLocation(8, 23),
// (9,23): error CS8388: An out variable cannot be declared as a ref local
// M1(out scoped ref readonly R r5);
Diagnostic(ErrorCode.ERR_OutVariableCannotBeByRef, "ref readonly R").WithLocation(9, 23),
// (10,16): error CS9061: The 'scoped' modifier cannot be used with discard.
// M1(out scoped R _);
Diagnostic(ErrorCode.ERR_ScopedDiscard, "scoped").WithLocation(10, 16),
// (11,16): error CS9061: The 'scoped' modifier cannot be used with discard.
// M1(out scoped var _);
Diagnostic(ErrorCode.ERR_ScopedDiscard, "scoped").WithLocation(11, 16),
// (12,16): error CS9061: The 'scoped' modifier cannot be used with discard.
// M1(out scoped ref R _);
Diagnostic(ErrorCode.ERR_ScopedDiscard, "scoped").WithLocation(12, 16),
// (12,23): error CS8388: An out variable cannot be declared as a ref local
// M1(out scoped ref R _);
Diagnostic(ErrorCode.ERR_OutVariableCannotBeByRef, "ref R").WithLocation(12, 23),
// (13,16): error CS9061: The 'scoped' modifier cannot be used with discard.
// M1(out scoped ref var _);
Diagnostic(ErrorCode.ERR_ScopedDiscard, "scoped").WithLocation(13, 16),
// (13,23): error CS8388: An out variable cannot be declared as a ref local
// M1(out scoped ref var _);
Diagnostic(ErrorCode.ERR_OutVariableCannotBeByRef, "ref var").WithLocation(13, 23),
// (14,16): error CS9061: The 'scoped' modifier cannot be used with discard.
// M1(out scoped ref readonly R _);
Diagnostic(ErrorCode.ERR_ScopedDiscard, "scoped").WithLocation(14, 16),
// (14,23): error CS8388: An out variable cannot be declared as a ref local
// M1(out scoped ref readonly R _);
Diagnostic(ErrorCode.ERR_OutVariableCannotBeByRef, "ref readonly R").WithLocation(14, 23),
// (15,16): error CS9061: The 'scoped' modifier cannot be used with discard.
// M1(out scoped ref readonly var _);
Diagnostic(ErrorCode.ERR_ScopedDiscard, "scoped").WithLocation(15, 16),
// (15,23): error CS8388: An out variable cannot be declared as a ref local
// M1(out scoped ref readonly var _);
Diagnostic(ErrorCode.ERR_OutVariableCannotBeByRef, "ref readonly var").WithLocation(15, 23),
// (17,23): error CS8388: An out variable cannot be declared as a ref local
// M1(out scoped ref var r21);
Diagnostic(ErrorCode.ERR_OutVariableCannotBeByRef, "ref var").WithLocation(17, 23),
// (18,23): error CS8388: An out variable cannot be declared as a ref local
// M1(out scoped ref readonly var r51);
Diagnostic(ErrorCode.ERR_OutVariableCannotBeByRef, "ref readonly var").WithLocation(18, 23),
// (20,16): error CS0246: The type or namespace name 'scoped' could not be found (are you missing a using directive or an assembly reference?)
// M1(out scoped _);
Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "scoped").WithArguments("scoped").WithLocation(20, 16),
// (21,16): error CS9061: The 'scoped' modifier cannot be used with discard.
// M1(out scoped scoped _);
Diagnostic(ErrorCode.ERR_ScopedDiscard, "scoped").WithLocation(21, 16),
// (21,23): error CS0246: The type or namespace name 'scoped' could not be found (are you missing a using directive or an assembly reference?)
// M1(out scoped scoped _);
Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "scoped").WithArguments("scoped").WithLocation(21, 23)
);
verify(comp);
static void verify(CSharpCompilation comp)
{
var tree = comp.SyntaxTrees[0];
var model = comp.GetSemanticModel(tree);
var decls = tree.GetRoot().DescendantNodes().OfType<SingleVariableDesignationSyntax>().ToArray();
var locals = decls.Select(d => model.GetDeclaredSymbol(d).GetSymbol<LocalSymbol>()).ToArray();
Assert.Equal(6, locals.Length);
VerifyLocalSymbol(locals[0], "scoped R r1", RefKind.None, ScopedKind.ScopedValue);
VerifyLocalSymbol(locals[1], "scoped R r2", RefKind.None, ScopedKind.ScopedValue);
VerifyLocalSymbol(locals[2], "scoped R r5", RefKind.None, ScopedKind.ScopedValue);
VerifyLocalSymbol(locals[3], "scoped R r11", RefKind.None, ScopedKind.ScopedValue);
VerifyLocalSymbol(locals[4], "scoped R r21", RefKind.None, ScopedKind.ScopedValue);
VerifyLocalSymbol(locals[5], "scoped R r51", RefKind.None, ScopedKind.ScopedValue);
foreach (var decl in decls)
{
var type = ((DeclarationExpressionSyntax)decl.Parent).Type;
Assert.True(SyntaxFacts.IsInTypeOnlyContext(type));
Assert.True(SyntaxFacts.IsInTypeOnlyContext(type.SkipScoped(out _)));
Assert.True(SyntaxFacts.IsInTypeOnlyContext(type.SkipScoped(out _).SkipRef()));
Assert.Null(model.GetSymbolInfo(type).Symbol);
Assert.Null(model.GetTypeInfo(type).Type);
type = type.SkipScoped(out _);
if (type is RefTypeSyntax refType)
{
Assert.Null(model.GetSymbolInfo(type).Symbol);
Assert.Null(model.GetTypeInfo(type).Type);
type = refType.Type;
}
Assert.Equal("R", model.GetSymbolInfo(type).Symbol.ToTestDisplayString());
Assert.Equal("R", model.GetTypeInfo(type).Type.ToTestDisplayString());
}
var discard = tree.GetRoot().DescendantNodes().OfType<DiscardDesignationSyntax>().ToArray();
Assert.Equal(8, discard.Length);
for (int i = 0; i < 6; i++)
{
var decl = discard[i];
Assert.Null(model.GetDeclaredSymbol(decl));
Assert.Null(model.GetSymbolInfo(decl).Symbol);
Assert.Null(model.GetTypeInfo(decl).Type);
var type = ((DeclarationExpressionSyntax)decl.Parent).Type;
Assert.True(SyntaxFacts.IsInTypeOnlyContext(type));
Assert.True(SyntaxFacts.IsInTypeOnlyContext(type.SkipScoped(out _)));
Assert.True(SyntaxFacts.IsInTypeOnlyContext(type.SkipScoped(out _).SkipRef()));
Assert.Null(model.GetSymbolInfo(type).Symbol);
Assert.Null(model.GetTypeInfo(type).Type);
type = type.SkipScoped(out _);
if (type is RefTypeSyntax refType)
{
Assert.Null(model.GetSymbolInfo(type).Symbol);
Assert.Null(model.GetTypeInfo(type).Type);
type = refType.Type;
}
Assert.Equal("R", model.GetSymbolInfo(type).Symbol.ToTestDisplayString());
Assert.Equal("R", model.GetTypeInfo(type).Type.ToTestDisplayString());
}
}
}
[Fact]
public void LocalScope_01_OutVar_Script()
{
var source =
@"#pragma warning disable 219
M1(out scoped R r1);
M1(out scoped ref R r2);
M1(out scoped ref readonly R r5);
M1(out scoped R _);
M1(out scoped var _);
M1(out scoped ref R _);
M1(out scoped ref var _);
M1(out scoped ref readonly R _);
M1(out scoped ref readonly var _);
M1(out scoped var r11);
M1(out scoped ref var r21);
M1(out scoped ref readonly var r51);
static void M1(out R r) => throw null;
ref struct R { }
";
var comp = CreateCompilation(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script);
comp.VerifyEmitDiagnostics(
// (3,8): error CS8345: Field or auto-implemented property cannot be of type 'R' unless it is an instance member of a ref struct.
// M1(out scoped R r1);
Diagnostic(ErrorCode.ERR_FieldAutoPropCantBeByRefLike, "scoped R").WithArguments("R").WithLocation(3, 8),
// (3,8): error CS1073: Unexpected token 'scoped'
// M1(out scoped R r1);
Diagnostic(ErrorCode.ERR_UnexpectedToken, "scoped").WithArguments("scoped").WithLocation(3, 8),
// (4,8): error CS8345: Field or auto-implemented property cannot be of type 'R' unless it is an instance member of a ref struct.
// M1(out scoped ref R r2);
Diagnostic(ErrorCode.ERR_FieldAutoPropCantBeByRefLike, "scoped ref R").WithArguments("R").WithLocation(4, 8),
// (4,8): error CS1073: Unexpected token 'scoped'
// M1(out scoped ref R r2);
Diagnostic(ErrorCode.ERR_UnexpectedToken, "scoped").WithArguments("scoped").WithLocation(4, 8),
// (4,15): error CS1073: Unexpected token 'ref'
// M1(out scoped ref R r2);
Diagnostic(ErrorCode.ERR_UnexpectedToken, "ref").WithArguments("ref").WithLocation(4, 15),
// (5,8): error CS8345: Field or auto-implemented property cannot be of type 'R' unless it is an instance member of a ref struct.
// M1(out scoped ref readonly R r5);
Diagnostic(ErrorCode.ERR_FieldAutoPropCantBeByRefLike, "scoped ref readonly R").WithArguments("R").WithLocation(5, 8),
// (5,8): error CS1073: Unexpected token 'scoped'
// M1(out scoped ref readonly R r5);
Diagnostic(ErrorCode.ERR_UnexpectedToken, "scoped").WithArguments("scoped").WithLocation(5, 8),
// (5,15): error CS1073: Unexpected token 'ref'
// M1(out scoped ref readonly R r5);
Diagnostic(ErrorCode.ERR_UnexpectedToken, "ref").WithArguments("ref").WithLocation(5, 15),
// (6,8): error CS9061: The 'scoped' modifier cannot be used with discard.
// M1(out scoped R _);
Diagnostic(ErrorCode.ERR_ScopedDiscard, "scoped").WithLocation(6, 8),
// (7,8): error CS9061: The 'scoped' modifier cannot be used with discard.
// M1(out scoped var _);
Diagnostic(ErrorCode.ERR_ScopedDiscard, "scoped").WithLocation(7, 8),
// (8,8): error CS9061: The 'scoped' modifier cannot be used with discard.
// M1(out scoped ref R _);
Diagnostic(ErrorCode.ERR_ScopedDiscard, "scoped").WithLocation(8, 8),
// (8,15): error CS8388: An out variable cannot be declared as a ref local
// M1(out scoped ref R _);
Diagnostic(ErrorCode.ERR_OutVariableCannotBeByRef, "ref R").WithLocation(8, 15),
// (9,8): error CS9061: The 'scoped' modifier cannot be used with discard.
// M1(out scoped ref var _);
Diagnostic(ErrorCode.ERR_ScopedDiscard, "scoped").WithLocation(9, 8),
// (9,15): error CS8388: An out variable cannot be declared as a ref local
// M1(out scoped ref var _);
Diagnostic(ErrorCode.ERR_OutVariableCannotBeByRef, "ref var").WithLocation(9, 15),
// (10,8): error CS9061: The 'scoped' modifier cannot be used with discard.
// M1(out scoped ref readonly R _);
Diagnostic(ErrorCode.ERR_ScopedDiscard, "scoped").WithLocation(10, 8),
// (10,15): error CS8388: An out variable cannot be declared as a ref local
// M1(out scoped ref readonly R _);
Diagnostic(ErrorCode.ERR_OutVariableCannotBeByRef, "ref readonly R").WithLocation(10, 15),
// (11,8): error CS9061: The 'scoped' modifier cannot be used with discard.
// M1(out scoped ref readonly var _);
Diagnostic(ErrorCode.ERR_ScopedDiscard, "scoped").WithLocation(11, 8),
// (11,15): error CS8388: An out variable cannot be declared as a ref local
// M1(out scoped ref readonly var _);
Diagnostic(ErrorCode.ERR_OutVariableCannotBeByRef, "ref readonly var").WithLocation(11, 15),
// (12,8): error CS8345: Field or auto-implemented property cannot be of type 'R' unless it is an instance member of a ref struct.
// M1(out scoped var r11);
Diagnostic(ErrorCode.ERR_FieldAutoPropCantBeByRefLike, "scoped var").WithArguments("R").WithLocation(12, 8),
// (12,8): error CS1073: Unexpected token 'scoped'
// M1(out scoped var r11);
Diagnostic(ErrorCode.ERR_UnexpectedToken, "scoped").WithArguments("scoped").WithLocation(12, 8),
// (13,8): error CS8345: Field or auto-implemented property cannot be of type 'R' unless it is an instance member of a ref struct.
// M1(out scoped ref var r21);
Diagnostic(ErrorCode.ERR_FieldAutoPropCantBeByRefLike, "scoped ref var").WithArguments("R").WithLocation(13, 8),
// (13,8): error CS1073: Unexpected token 'scoped'
// M1(out scoped ref var r21);
Diagnostic(ErrorCode.ERR_UnexpectedToken, "scoped").WithArguments("scoped").WithLocation(13, 8),
// (13,15): error CS1073: Unexpected token 'ref'
// M1(out scoped ref var r21);
Diagnostic(ErrorCode.ERR_UnexpectedToken, "ref").WithArguments("ref").WithLocation(13, 15),
// (14,8): error CS8345: Field or auto-implemented property cannot be of type 'R' unless it is an instance member of a ref struct.
// M1(out scoped ref readonly var r51);
Diagnostic(ErrorCode.ERR_FieldAutoPropCantBeByRefLike, "scoped ref readonly var").WithArguments("R").WithLocation(14, 8),
// (14,8): error CS1073: Unexpected token 'scoped'
// M1(out scoped ref readonly var r51);
Diagnostic(ErrorCode.ERR_UnexpectedToken, "scoped").WithArguments("scoped").WithLocation(14, 8),
// (14,15): error CS1073: Unexpected token 'ref'
// M1(out scoped ref readonly var r51);
Diagnostic(ErrorCode.ERR_UnexpectedToken, "ref").WithArguments("ref").WithLocation(14, 15)
);
verify(comp);
static void verify(CSharpCompilation comp)
{
var tree = comp.SyntaxTrees[0];
var model = comp.GetSemanticModel(tree);
var decls = tree.GetRoot().DescendantNodes().OfType<SingleVariableDesignationSyntax>().ToArray();
Assert.Equal(6, decls.Length);
foreach (var decl in decls)
{
var f = model.GetDeclaredSymbol(decl).GetSymbol<FieldSymbol>();
Assert.Equal(RefKind.None, f.RefKind);
Assert.Equal("Script.R", f.Type.ToTestDisplayString());
var type = ((DeclarationExpressionSyntax)decl.Parent).Type;
Assert.Null(model.GetSymbolInfo(type).Symbol);
Assert.Null(model.GetTypeInfo(type).Type);
type = type.SkipScoped(out _);
if (type is RefTypeSyntax refType)
{
Assert.Null(model.GetSymbolInfo(type).Symbol);
Assert.Null(model.GetTypeInfo(type).Type);
type = refType.Type;
}
Assert.Equal("Script.R", model.GetSymbolInfo(type).Symbol.ToTestDisplayString());
Assert.Equal("Script.R", model.GetTypeInfo(type).Type.ToTestDisplayString());
}
var discard = tree.GetRoot().DescendantNodes().OfType<DiscardDesignationSyntax>().ToArray();
Assert.Equal(6, discard.Length);
foreach (var decl in discard)
{
Assert.Null(model.GetDeclaredSymbol(decl));
Assert.Null(model.GetSymbolInfo(decl).Symbol);
Assert.Null(model.GetTypeInfo(decl).Type);
var type = ((DeclarationExpressionSyntax)decl.Parent).Type;
Assert.Null(model.GetSymbolInfo(type).Symbol);
Assert.Null(model.GetTypeInfo(type).Type);
type = type.SkipScoped(out _);
if (type is RefTypeSyntax refType)
{
Assert.Null(model.GetSymbolInfo(type).Symbol);
Assert.Null(model.GetTypeInfo(type).Type);
type = refType.Type;
}
Assert.Equal("Script.R", model.GetSymbolInfo(type).Symbol.ToTestDisplayString());
Assert.Equal("Script.R", model.GetTypeInfo(type).Type.ToTestDisplayString());
}
}
}
[Fact]
public void LocalScope_02()
{
var source =
@"ref struct R { }
class Program
{
static void Main()
{
scoped scoped R x = default;
scoped scoped ref R z = ref x;
}
}";
var comp = CreateCompilation(source);
// Duplicate scoped modifiers result are parse errors rather than binding errors.
comp.VerifyDiagnostics(
// (6,16): error CS0118: 'scoped' is a variable but is used like a type
// scoped scoped R x = default;
Diagnostic(ErrorCode.ERR_BadSKknown, "scoped").WithArguments("scoped", "variable", "type").WithLocation(6, 16),
// (6,23): warning CS0168: The variable 'R' is declared but never used
// scoped scoped R x = default;
Diagnostic(ErrorCode.WRN_UnreferencedVar, "R").WithArguments("R").WithLocation(6, 23),
// (6,25): error CS1002: ; expected
// scoped scoped R x = default;
Diagnostic(ErrorCode.ERR_SemicolonExpected, "x").WithLocation(6, 25),
// (6,25): error CS0103: The name 'x' does not exist in the current context
// scoped scoped R x = default;
Diagnostic(ErrorCode.ERR_NameNotInContext, "x").WithArguments("x").WithLocation(6, 25),
// (7,9): error CS0118: 'scoped' is a variable but is used like a type
// scoped scoped ref R z = ref x;
Diagnostic(ErrorCode.ERR_BadSKknown, "scoped").WithArguments("scoped", "variable", "type").WithLocation(7, 9),
// (7,16): warning CS0168: The variable 'scoped' is declared but never used
// scoped scoped ref R z = ref x;
Diagnostic(ErrorCode.WRN_UnreferencedVar, "scoped").WithArguments("scoped").WithLocation(7, 16),
// (7,23): error CS1002: ; expected
// scoped scoped ref R z = ref x;
Diagnostic(ErrorCode.ERR_SemicolonExpected, "ref").WithLocation(7, 23),
// (7,37): error CS0103: The name 'x' does not exist in the current context
// scoped scoped ref R z = ref x;
Diagnostic(ErrorCode.ERR_NameNotInContext, "x").WithArguments("x").WithLocation(7, 37)
);
}
[Fact]
public void LocalScope_03()
{
var source =
@"scoped scoped R x = default;
scoped scoped ref R z = ref x;
ref struct R { }
";
var comp = CreateCompilation(source);
// Duplicate scoped modifiers result are parse errors rather than binding errors.
comp.VerifyDiagnostics(
// (1,8): error CS0118: 'scoped' is a variable but is used like a type
// scoped scoped R x = default;
Diagnostic(ErrorCode.ERR_BadSKknown, "scoped").WithArguments("scoped", "variable", "type").WithLocation(1, 8),
// (1,15): warning CS0168: The variable 'R' is declared but never used
// scoped scoped R x = default;
Diagnostic(ErrorCode.WRN_UnreferencedVar, "R").WithArguments("R").WithLocation(1, 15),
// (1,17): error CS1003: Syntax error, ',' expected
// scoped scoped R x = default;
Diagnostic(ErrorCode.ERR_SyntaxError, "x").WithArguments(",").WithLocation(1, 17),
// (2,1): error CS0118: 'scoped' is a variable but is used like a type
// scoped scoped ref R z = ref x;
Diagnostic(ErrorCode.ERR_BadSKknown, "scoped").WithArguments("scoped", "variable", "type").WithLocation(2, 1),
// (2,8): warning CS0168: The variable 'scoped' is declared but never used
// scoped scoped ref R z = ref x;
Diagnostic(ErrorCode.WRN_UnreferencedVar, "scoped").WithArguments("scoped").WithLocation(2, 8),
// (2,15): error CS1003: Syntax error, ',' expected
// scoped scoped ref R z = ref x;
Diagnostic(ErrorCode.ERR_SyntaxError, "ref").WithArguments(",").WithLocation(2, 15));
}
[Fact]
public void LocalScope_04()
{
var source =
@"scoped s1 = default;
ref scoped s2 = ref s1; // 1
ref @scoped s3 = ref s1;
scoped scoped s4 = default; // 2
scoped ref scoped s5 = ref s1; // 3
scoped ref @scoped s6 = ref s1; // 4
ref struct @scoped { } // 5
";
var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10);
comp.VerifyEmitDiagnostics(
// (4,1): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater.
// scoped scoped s4 = default; // 2
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "scoped").WithArguments("ref fields", "11.0").WithLocation(4, 1),
// (4,15): warning CS0219: The variable 's4' is assigned but its value is never used
// scoped scoped s4 = default; // 2
Diagnostic(ErrorCode.WRN_UnreferencedVarAssg, "s4").WithArguments("s4").WithLocation(4, 15),
// (5,1): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater.
// scoped ref scoped s5 = ref s1; // 3
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "scoped").WithArguments("ref fields", "11.0").WithLocation(5, 1),
// (6,1): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater.
// scoped ref @scoped s6 = ref s1; // 4
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "scoped").WithArguments("ref fields", "11.0").WithLocation(6, 1)
);
verify(comp);
comp = CreateCompilation(source);
comp.VerifyDiagnostics(
// (4,15): warning CS0219: The variable 's4' is assigned but its value is never used
// scoped scoped s4 = default; // 2
Diagnostic(ErrorCode.WRN_UnreferencedVarAssg, "s4").WithArguments("s4").WithLocation(4, 15)
);
verify(comp);
static void verify(CSharpCompilation comp)
{
var tree = comp.SyntaxTrees[0];
var model = comp.GetSemanticModel(tree);
var decls = tree.GetRoot().DescendantNodes().OfType<VariableDeclaratorSyntax>().ToArray();
var locals = decls.Select(d => model.GetDeclaredSymbol(d).GetSymbol<LocalSymbol>()).ToArray();
VerifyLocalSymbol(locals[0], "scoped s1", RefKind.None, ScopedKind.None);
VerifyLocalSymbol(locals[1], "ref scoped s2", RefKind.Ref, ScopedKind.None);
VerifyLocalSymbol(locals[2], "ref scoped s3", RefKind.Ref, ScopedKind.None);
VerifyLocalSymbol(locals[3], "scoped scoped s4", RefKind.None, ScopedKind.ScopedValue);
VerifyLocalSymbol(locals[4], "scoped ref scoped s5", RefKind.Ref, ScopedKind.ScopedRef);
VerifyLocalSymbol(locals[5], "scoped ref scoped s6", RefKind.Ref, ScopedKind.ScopedRef);
}
}
[Fact]
public void LocalScope_04_For()
{
var source =
@"for (scoped s1 = default;;) {
for (ref scoped s2 = ref s1;;) {break;} // 1
for (ref @scoped s3 = ref s1;;) {break;}
for (scoped scoped s4 = default;;) {break;} // 2
for (scoped ref scoped s5 = ref s1;;) {break;} // 3
for (scoped ref @scoped s6 = ref s1;;) {break;} // 4
}
ref struct @scoped { } // 5
";
var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10);
comp.VerifyEmitDiagnostics(
// (4,10): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater.
// for (scoped scoped s4 = default;;) {break;} // 2
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "scoped").WithArguments("ref fields", "11.0").WithLocation(4, 10),
// (4,24): warning CS0219: The variable 's4' is assigned but its value is never used
// for (scoped scoped s4 = default;;) {break;} // 2
Diagnostic(ErrorCode.WRN_UnreferencedVarAssg, "s4").WithArguments("s4").WithLocation(4, 24),
// (5,10): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater.
// for (scoped ref scoped s5 = ref s1;;) {break;} // 3
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "scoped").WithArguments("ref fields", "11.0").WithLocation(5, 10),
// (6,10): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater.
// for (scoped ref @scoped s6 = ref s1;;) {break;} // 4
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "scoped").WithArguments("ref fields", "11.0").WithLocation(6, 10)
);
verify(comp);
comp = CreateCompilation(source);
comp.VerifyDiagnostics(
// (4,24): warning CS0219: The variable 's4' is assigned but its value is never used
// for (scoped scoped s4 = default;;) {break;} // 2
Diagnostic(ErrorCode.WRN_UnreferencedVarAssg, "s4").WithArguments("s4").WithLocation(4, 24)
);
verify(comp);
static void verify(CSharpCompilation comp)
{
var tree = comp.SyntaxTrees[0];
var model = comp.GetSemanticModel(tree);
var decls = tree.GetRoot().DescendantNodes().OfType<VariableDeclaratorSyntax>().ToArray();
var locals = decls.Select(d => model.GetDeclaredSymbol(d).GetSymbol<LocalSymbol>()).ToArray();
VerifyLocalSymbol(locals[0], "scoped s1", RefKind.None, ScopedKind.None);
VerifyLocalSymbol(locals[1], "ref scoped s2", RefKind.Ref, ScopedKind.None);
VerifyLocalSymbol(locals[2], "ref scoped s3", RefKind.Ref, ScopedKind.None);
VerifyLocalSymbol(locals[3], "scoped scoped s4", RefKind.None, ScopedKind.ScopedValue);
VerifyLocalSymbol(locals[4], "scoped ref scoped s5", RefKind.Ref, ScopedKind.ScopedRef);
VerifyLocalSymbol(locals[5], "scoped ref scoped s6", RefKind.Ref, ScopedKind.ScopedRef);
}
}
[Fact]
public void LocalScope_04_Deconstruction()
{
var source =
@"
var r = new RR();
(scoped s1, var a) = r;
(@scoped s3, var b) = r;
(scoped scoped s4, var c) = r;
(scoped @scoped s6, var d) = r;
(scoped _, var e) = r;
(scoped scoped _, var f) = r;
ref struct @scoped { }
class RR
{
public void Deconstruct(out @scoped x, out int y) => throw null;
}
";
var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10);
comp.VerifyEmitDiagnostics(
// (5,2): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater.
// (scoped scoped s4, var c) = r;
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "scoped").WithArguments("ref fields", "11.0").WithLocation(5, 2),
// (6,2): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater.
// (scoped @scoped s6, var d) = r;
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "scoped").WithArguments("ref fields", "11.0").WithLocation(6, 2),
// (9,2): error CS9061: The 'scoped' modifier cannot be used with discard.
// (scoped scoped _, var f) = r;
Diagnostic(ErrorCode.ERR_ScopedDiscard, "scoped").WithLocation(9, 2)
);
verify(comp);
comp = CreateCompilation(source);
comp.VerifyDiagnostics(
// (9,2): error CS9061: The 'scoped' modifier cannot be used with discard.
// (scoped scoped _, var f) = r;
Diagnostic(ErrorCode.ERR_ScopedDiscard, "scoped").WithLocation(9, 2)
);
verify(comp);
static void verify(CSharpCompilation comp)
{
var tree = comp.SyntaxTrees[0];
var model = comp.GetSemanticModel(tree);
var decls = tree.GetRoot().DescendantNodes().OfType<SingleVariableDesignationSyntax>().ToArray();
var locals = decls.Select(d => model.GetDeclaredSymbol(d).GetSymbol<LocalSymbol>()).ToArray();
VerifyLocalSymbol(locals[0], "scoped s1", RefKind.None, ScopedKind.None);
VerifyLocalSymbol(locals[2], "scoped s3", RefKind.None, ScopedKind.None);
VerifyLocalSymbol(locals[4], "scoped scoped s4", RefKind.None, ScopedKind.ScopedValue);
VerifyLocalSymbol(locals[6], "scoped scoped s6", RefKind.None, ScopedKind.ScopedValue);
}
}
[Fact]
public void LocalScope_04_OutVar()
{
var source =
@"
M(out scoped s1);
M(out @scoped s3);
M(out scoped scoped s4);
M(out scoped @scoped s6);
void M(out scoped x) => throw null;
ref struct @scoped { }
";
var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10);
comp.VerifyEmitDiagnostics(
// (4,7): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater.
// M(out scoped scoped s4);
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "scoped").WithArguments("ref fields", "11.0").WithLocation(4, 7),
// (5,7): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater.
// M(out scoped @scoped s6);
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "scoped").WithArguments("ref fields", "11.0").WithLocation(5, 7)
);
verify(comp);
comp = CreateCompilation(source);
comp.VerifyDiagnostics();
verify(comp);
static void verify(CSharpCompilation comp)
{
var tree = comp.SyntaxTrees[0];
var model = comp.GetSemanticModel(tree);
var decls = tree.GetRoot().DescendantNodes().OfType<SingleVariableDesignationSyntax>().ToArray();
var locals = decls.Select(d => model.GetDeclaredSymbol(d).GetSymbol<LocalSymbol>()).ToArray();
Assert.Equal(4, locals.Length);
VerifyLocalSymbol(locals[0], "scoped s1", RefKind.None, ScopedKind.None);
VerifyLocalSymbol(locals[1], "scoped s3", RefKind.None, ScopedKind.None);
VerifyLocalSymbol(locals[2], "scoped scoped s4", RefKind.None, ScopedKind.ScopedValue);
VerifyLocalSymbol(locals[3], "scoped scoped s6", RefKind.None, ScopedKind.ScopedValue);
}
}
[Theory]
[InlineData(LanguageVersion.CSharp10)]
[InlineData(LanguageVersion.CSharp11)]
public void LocalScope_05(LanguageVersion langVersion)
{
var source =
@"bool scoped;
scoped = true;
";
var comp = CreateCompilation(source, parseOptions: TestOptions.Regular.WithLanguageVersion(langVersion));
comp.VerifyDiagnostics(
// (1,6): warning CS0219: The variable 'scoped' is assigned but its value is never used
// bool scoped;
Diagnostic(ErrorCode.WRN_UnreferencedVarAssg, "scoped").WithArguments("scoped").WithLocation(1, 6));
var tree = comp.SyntaxTrees[0];
var model = comp.GetSemanticModel(tree);
var decls = tree.GetRoot().DescendantNodes().OfType<VariableDeclaratorSyntax>().ToArray();
var locals = decls.Select(d => model.GetDeclaredSymbol(d).GetSymbol<LocalSymbol>()).ToArray();
VerifyLocalSymbol(locals[0], "System.Boolean scoped", RefKind.None, ScopedKind.None);
}
[Theory]
[InlineData(LanguageVersion.CSharp10)]
[InlineData(LanguageVersion.CSharp11)]
public void LocalScope_05_For(LanguageVersion langVersion)
{
var source =
@"for (bool scoped;;) {
for (scoped = true;;) {break;}
}
";
var comp = CreateCompilation(source, parseOptions: TestOptions.Regular.WithLanguageVersion(langVersion));
comp.VerifyDiagnostics(
// (1,11): warning CS0219: The variable 'scoped' is assigned but its value is never used
// for (bool scoped;;) {
Diagnostic(ErrorCode.WRN_UnreferencedVarAssg, "scoped").WithArguments("scoped").WithLocation(1, 11)
);
var tree = comp.SyntaxTrees[0];
var model = comp.GetSemanticModel(tree);
var decls = tree.GetRoot().DescendantNodes().OfType<VariableDeclaratorSyntax>().ToArray();
var locals = decls.Select(d => model.GetDeclaredSymbol(d).GetSymbol<LocalSymbol>()).ToArray();
VerifyLocalSymbol(locals[0], "System.Boolean scoped", RefKind.None, ScopedKind.None);
}
[Theory]
[InlineData(LanguageVersion.CSharp10)]
[InlineData(LanguageVersion.CSharp11)]
public void LocalScope_05_Deconstruction(LanguageVersion langVersion)
{
var source =
@"
(bool scoped, var x) = (true, 0);
";
var comp = CreateCompilation(source, parseOptions: TestOptions.Regular.WithLanguageVersion(langVersion));
comp.VerifyDiagnostics();
var tree = comp.SyntaxTrees[0];
var model = comp.GetSemanticModel(tree);
var decls = tree.GetRoot().DescendantNodes().OfType<SingleVariableDesignationSyntax>().ToArray();
var locals = decls.Select(d => model.GetDeclaredSymbol(d).GetSymbol<LocalSymbol>()).ToArray();
VerifyLocalSymbol(locals[0], "System.Boolean scoped", RefKind.None, ScopedKind.None);
}
[Theory]
[InlineData(LanguageVersion.CSharp10)]
[InlineData(LanguageVersion.CSharp11)]
public void LocalScope_05_OutVar(LanguageVersion langVersion)
{
var source =
@"
M(out bool scoped);
void M(out bool x) => throw null;
";
var comp = CreateCompilation(source, parseOptions: TestOptions.Regular.WithLanguageVersion(langVersion));
comp.VerifyDiagnostics();
var tree = comp.SyntaxTrees[0];
var model = comp.GetSemanticModel(tree);
var decls = tree.GetRoot().DescendantNodes().OfType<SingleVariableDesignationSyntax>().ToArray();
var locals = decls.Select(d => model.GetDeclaredSymbol(d).GetSymbol<LocalSymbol>()).ToArray();
VerifyLocalSymbol(locals[0], "System.Boolean scoped", RefKind.None, ScopedKind.None);
}
[Fact]
public void LocalScope_06()
{
var source =
@"ref struct R<T> { }
class Program
{
static void M(R<int> r0)
{
scoped var r1 = new R<int>();
scoped ref var r3 = ref r0;
}
}";
var comp = CreateCompilation(source);
comp.VerifyDiagnostics(
// (6,20): warning CS0219: The variable 'r1' is assigned but its value is never used
// scoped var r1 = new R<int>();
Diagnostic(ErrorCode.WRN_UnreferencedVarAssg, "r1").WithArguments("r1").WithLocation(6, 20)
);
verifyModel(comp);
comp = CreateCompilation(source, parseOptions: TestOptions.RegularDefault.WithFeature("run-nullable-analysis", "never"));
verifyModel(comp);
static void verifyModel(CSharpCompilation comp)
{
var tree = comp.SyntaxTrees[0];
var model = comp.GetSemanticModel(tree);
var decls = tree.GetRoot().DescendantNodes().OfType<VariableDeclaratorSyntax>().ToArray();
var locals = decls.Select(d => model.GetDeclaredSymbol(d).GetSymbol<LocalSymbol>()).ToArray();
foreach (SourceLocalSymbol local in locals)
{
Assert.True(local.IsVar);
Assert.Equal("R<System.Int32>", local.Type.ToTestDisplayString());
}
VerifyLocalSymbol(locals[0], "scoped R<System.Int32> r1", RefKind.None, ScopedKind.ScopedValue);
VerifyLocalSymbol(locals[1], "scoped ref R<System.Int32> r3", RefKind.Ref, ScopedKind.ScopedRef);
foreach (var decl in decls)
{
var type = ((VariableDeclarationSyntax)decl.Parent).Type;
Assert.Null(model.GetSymbolInfo(type).Symbol);
Assert.Null(model.GetTypeInfo(type).Type);
type = type.SkipScoped(out _);
if (type is RefTypeSyntax refType)
{
Assert.Null(model.GetSymbolInfo(type).Symbol);
Assert.Null(model.GetTypeInfo(type).Type);
type = refType.Type;
}
Assert.Equal("R<System.Int32>", model.GetSymbolInfo(type).Symbol.ToTestDisplayString());
Assert.Equal("R<System.Int32>", model.GetTypeInfo(type).Type.ToTestDisplayString());
}
}
}
[Fact]
public void LocalScope_06_For()
{
var source =
@"ref struct R<T> { }
class Program
{
static void M(R<int> r0)
{
for (scoped var r1 = new R<int>();;) break;
for (scoped ref var r3 = ref r0;;) break;
}
}";
var comp = CreateCompilation(source);
comp.VerifyDiagnostics(
// (6,25): warning CS0219: The variable 'r1' is assigned but its value is never used
// for (scoped var r1 = new R<int>();;) break;
Diagnostic(ErrorCode.WRN_UnreferencedVarAssg, "r1").WithArguments("r1").WithLocation(6, 25)
);
verifyModel(comp);
comp = CreateCompilation(source, parseOptions: TestOptions.RegularDefault.WithFeature("run-nullable-analysis", "never"));
verifyModel(comp);
static void verifyModel(CSharpCompilation comp)
{
var tree = comp.SyntaxTrees[0];
var model = comp.GetSemanticModel(tree);
var decls = tree.GetRoot().DescendantNodes().OfType<VariableDeclaratorSyntax>().ToArray();
var locals = decls.Select(d => model.GetDeclaredSymbol(d).GetSymbol<LocalSymbol>()).ToArray();
foreach (SourceLocalSymbol local in locals)
{
Assert.True(local.IsVar);
Assert.Equal("R<System.Int32>", local.Type.ToTestDisplayString());
}
VerifyLocalSymbol(locals[0], "scoped R<System.Int32> r1", RefKind.None, ScopedKind.ScopedValue);
VerifyLocalSymbol(locals[1], "scoped ref R<System.Int32> r3", RefKind.Ref, ScopedKind.ScopedRef);
foreach (var decl in decls)
{
var type = ((VariableDeclarationSyntax)decl.Parent).Type;
Assert.Null(model.GetSymbolInfo(type).Symbol);
Assert.Null(model.GetTypeInfo(type).Type);
type = type.SkipScoped(out _);
if (type is RefTypeSyntax refType)
{
Assert.Null(model.GetSymbolInfo(type).Symbol);
Assert.Null(model.GetTypeInfo(type).Type);
type = refType.Type;
}
Assert.Equal("R<System.Int32>", model.GetSymbolInfo(type).Symbol.ToTestDisplayString());
Assert.Equal("R<System.Int32>", model.GetTypeInfo(type).Type.ToTestDisplayString());
}
}
}
[Fact]
public void LocalScope_06_Deconstruction()
{
var source =
@"ref struct R<T> { }
class Program
{
static void M(R<int> r0)
{
(scoped var r1, var a) = new RR(new R<int>());
(scoped ref var r3, var b) = new RR(ref r0);
scoped R<int> r4;
int c;
(r4, c) = new RR(ref r0);
}
}
ref struct RR
{
public RR(R<int> x){}
public RR(ref R<int> x){}
public void Deconstruct(out R<int> x, out int y) => throw null;
}
";
var comp = CreateCompilation(source);
comp.VerifyDiagnostics(
// (7,17): error CS9072: A deconstruction variable cannot be declared as a ref local
// (scoped ref var r3, var b) = new RR(ref r0);
Diagnostic(ErrorCode.ERR_DeconstructVariableCannotBeByRef, "ref").WithLocation(7, 17)
);
verifyModel(comp);
comp = CreateCompilation(source, parseOptions: TestOptions.RegularDefault.WithFeature("run-nullable-analysis", "never"));
verifyModel(comp);
static void verifyModel(CSharpCompilation comp)
{
var tree = comp.SyntaxTrees[0];
var model = comp.GetSemanticModel(tree);
var decls = tree.GetRoot().DescendantNodes().OfType<SingleVariableDesignationSyntax>().ToArray();
var locals = decls.Select(d => model.GetDeclaredSymbol(d).GetSymbol<SourceLocalSymbol>()).ToArray();
for (int i = 0; i < 3; i += 2)
{
Assert.True(locals[i].IsVar);
Assert.Equal("R<System.Int32>", locals[i].Type.ToTestDisplayString());
}
VerifyLocalSymbol(locals[0], "scoped R<System.Int32> r1", RefKind.None, ScopedKind.ScopedValue);
VerifyLocalSymbol(locals[2], "scoped R<System.Int32> r3", RefKind.None, ScopedKind.ScopedValue);
for (int i = 0; i < 3; i += 2)
{
var decl = decls[i];
var type = ((DeclarationExpressionSyntax)decl.Parent).Type;
Assert.Null(model.GetSymbolInfo(type).Symbol);
Assert.Null(model.GetTypeInfo(type).Type);
type = type.SkipScoped(out _);
if (type is RefTypeSyntax refType)
{
Assert.Null(model.GetSymbolInfo(type).Symbol);
Assert.Null(model.GetTypeInfo(type).Type);
type = refType.Type;
}
Assert.Equal("R<System.Int32>", model.GetSymbolInfo(type).Symbol.ToTestDisplayString());
Assert.Equal("R<System.Int32>", model.GetTypeInfo(type).Type.ToTestDisplayString());
}
}
}
[Fact]
public void LocalScope_06_OutVar()
{
var source =
@"ref struct R<T> { }
class Program
{
static void M(R<int> r0)
{
M1(out scoped var r1, new R<int>());
M2(out scoped ref var r3, ref r0);
scoped R<int> r4;
M2(out r4, ref r0);
}
static void M1(out R<int> y, R<int> x) => throw null;
static void M2(out R<int> y, ref R<int> x) => throw null;
}";
var comp = CreateCompilation(source);
comp.VerifyDiagnostics(
// (7,23): error CS8388: An out variable cannot be declared as a ref local
// M2(out scoped ref var r3, ref r0);
Diagnostic(ErrorCode.ERR_OutVariableCannotBeByRef, "ref var").WithLocation(7, 23)
);
verifyModel(comp);
comp = CreateCompilation(source, parseOptions: TestOptions.RegularDefault.WithFeature("run-nullable-analysis", "never"));
verifyModel(comp);
static void verifyModel(CSharpCompilation comp)
{
var tree = comp.SyntaxTrees[0];
var model = comp.GetSemanticModel(tree);
var decls = tree.GetRoot().DescendantNodes().OfType<SingleVariableDesignationSyntax>().ToArray();
var locals = decls.Select(d => model.GetDeclaredSymbol(d).GetSymbol<LocalSymbol>()).ToArray();
foreach (SourceLocalSymbol local in locals)
{
Assert.True(local.IsVar);
Assert.Equal("R<System.Int32>", local.Type.ToTestDisplayString());
}
VerifyLocalSymbol(locals[0], "scoped R<System.Int32> r1", RefKind.None, ScopedKind.ScopedValue);
VerifyLocalSymbol(locals[1], "scoped R<System.Int32> r3", RefKind.None, ScopedKind.ScopedValue);
foreach (var decl in decls)
{
var type = ((DeclarationExpressionSyntax)decl.Parent).Type;
Assert.Null(model.GetSymbolInfo(type).Symbol);
Assert.Null(model.GetTypeInfo(type).Type);
type = type.SkipScoped(out _);
if (type is RefTypeSyntax refType)
{
Assert.Null(model.GetSymbolInfo(type).Symbol);
Assert.Null(model.GetTypeInfo(type).Type);
type = refType.Type;
}
Assert.Equal("R<System.Int32>", model.GetSymbolInfo(type).Symbol.ToTestDisplayString());
Assert.Equal("R<System.Int32>", model.GetTypeInfo(type).Type.ToTestDisplayString());
}
}
}
[Fact]
public void LocalScope_07()
{
var source =
@"
class Program
{
static void Test(ref int x)
{
ref int a = ref x;
scoped extern ref int b = ref x;
}
}
";
var comp = CreateCompilation(source);
comp.VerifyDiagnostics(
// (7,9): error CS0103: The name 'scoped' does not exist in the current context
// scoped extern ref int b = ref x;
Diagnostic(ErrorCode.ERR_NameNotInContext, "scoped").WithArguments("scoped").WithLocation(7, 9),
// (7,16): error CS1002: ; expected
// scoped extern ref int b = ref x;
Diagnostic(ErrorCode.ERR_SemicolonExpected, "extern").WithLocation(7, 16),
// (7,16): error CS0106: The modifier 'extern' is not valid for this item
// scoped extern ref int b = ref x;
Diagnostic(ErrorCode.ERR_BadMemberFlag, "extern").WithArguments("extern").WithLocation(7, 16)
);
var tree = comp.SyntaxTrees[0];
var model = comp.GetSemanticModel(tree);
var decls = tree.GetRoot().DescendantNodes().OfType<VariableDeclaratorSyntax>().ToArray();
var locals = decls.Select(d => model.GetDeclaredSymbol(d).GetSymbol<LocalSymbol>()).ToArray();
Assert.Equal(2, locals.Length);
VerifyLocalSymbol(locals[0], "ref System.Int32 a", RefKind.Ref, ScopedKind.None);
VerifyLocalSymbol(locals[1], "ref System.Int32 b", RefKind.Ref, ScopedKind.None);
}
[Fact]
public void LocalScope_08()
{
var source =
@"
class Program
{
static void Test(ref int x)
{
scoped ref int[M(out var b)] a;
b++;
}
static int M(out int x) => throw null;
}
";
var comp = CreateCompilation(source);
comp.VerifyDiagnostics(
// (6,23): error CS0270: Array size cannot be specified in a variable declaration (try initializing with a 'new' expression)
// scoped ref int[M(out var b)] a;
Diagnostic(ErrorCode.ERR_ArraySizeInDeclaration, "[M(out var b)]").WithLocation(6, 23),
// (6,38): error CS8174: A declaration of a by-reference variable must have an initializer
// scoped ref int[M(out var b)] a;
Diagnostic(ErrorCode.ERR_ByReferenceVariableMustBeInitialized, "a").WithLocation(6, 38),
// (6,38): warning CS0168: The variable 'a' is declared but never used
// scoped ref int[M(out var b)] a;
Diagnostic(ErrorCode.WRN_UnreferencedVar, "a").WithArguments("a").WithLocation(6, 38),
// (7,9): error CS0165: Use of unassigned local variable 'b'
// b++;
Diagnostic(ErrorCode.ERR_UseDefViolation, "b").WithArguments("b").WithLocation(7, 9)
);
}
[Fact]
public void LocalScope_08_For()
{
var source =
@"
class Program
{
static void Test(ref int x)
{
for (scoped ref int[M(out var b)] a;;) {
b++;
}
}
static int M(out int x) => throw null;
}
";
var comp = CreateCompilation(source);
comp.VerifyDiagnostics(
// (6,28): error CS0270: Array size cannot be specified in a variable declaration (try initializing with a 'new' expression)
// for (scoped ref int[M(out var b)] a;;) {
Diagnostic(ErrorCode.ERR_ArraySizeInDeclaration, "[M(out var b)]").WithLocation(6, 28),
// (6,43): error CS8174: A declaration of a by-reference variable must have an initializer
// for (scoped ref int[M(out var b)] a;;) {
Diagnostic(ErrorCode.ERR_ByReferenceVariableMustBeInitialized, "a").WithLocation(6, 43),
// (6,43): warning CS0168: The variable 'a' is declared but never used
// for (scoped ref int[M(out var b)] a;;) {
Diagnostic(ErrorCode.WRN_UnreferencedVar, "a").WithArguments("a").WithLocation(6, 43),
// (7,13): error CS0165: Use of unassigned local variable 'b'
// b++;
Diagnostic(ErrorCode.ERR_UseDefViolation, "b").WithArguments("b").WithLocation(7, 13)
);
}
[WorkItem(64009, "https://github.com/dotnet/roslyn/issues/64009")]
[Fact]
public void LocalScope_09()
{
var source =
@"{
scoped s1 = default;
scoped ref @scoped s2 = ref s1;
}
ref struct @scoped { }
";
var comp = CreateCompilation(source);
comp.VerifyDiagnostics();
}
[WorkItem(64009, "https://github.com/dotnet/roslyn/issues/64009")]
[Fact]
public void LocalScope_09_For_01()
{
var source =
@"for (scoped s1 = default;;) {
scoped ref @scoped s2 = ref s1;
}
ref struct @scoped { }
";
var comp = CreateCompilation(source);
comp.VerifyDiagnostics();
}
[WorkItem(64009, "https://github.com/dotnet/roslyn/issues/64009")]
[Fact]
public void LocalScope_09_For_02()
{
var source =
@"scoped s1 = default;
for (scoped ref @scoped s2 = ref s1;;) break;
ref struct @scoped { }
";
var comp = CreateCompilation(source);
comp.VerifyDiagnostics();
}
[Fact]
public void LocalScope_10()
{
var source =
@"{
int i = 0;
S s1 = new S(ref i);
scoped S s2 = s1;
}
ref struct S
{
public S(ref int i) { }
}
";
var comp = CreateCompilation(source);
comp.VerifyDiagnostics();
}
[Fact]
public void LocalScope_10_For_01()
{
var source =
@"int i = 0;
S s1 = new S(ref i);
for (scoped S s2 = s1;;) break;
ref struct S
{
public S(ref int i) { }
}
";
var comp = CreateCompilation(source);
comp.VerifyDiagnostics();
}
[Fact]
public void LocalScope_10_For_02()
{
var source =
@"int i = 0;
for (S s1 = new S(ref i);;) {
scoped S s2 = s1;
break;
}
ref struct S
{
public S(ref int i) { }
}
";
var comp = CreateCompilation(source);
comp.VerifyDiagnostics();
}
[Fact]
public void LocalScope_10_Deconstruction()
{
var source =
@"{
int i = 0;
S s1 = new S(ref i);
(scoped S s2, var a) = s1;
scoped S s3;
int b;
(s3, b) = s1;
}
ref struct S
{
public S(ref int i) { }
public void Deconstruct(out S x, out int y) => throw null;
}
";
var comp = CreateCompilation(source);
comp.VerifyDiagnostics();
}
[Fact]
public void LocalScope_10_OutVar()
{
var source =
@"{
int i = 0;
S s1 = new S(ref i);
s1.M(out scoped S s2);
scoped S s3;
s1.M(out s3);
}
ref struct S
{
public S(ref int i) { }
public void M(out S x) => throw null;
}
";
var comp = CreateCompilation(source);
comp.VerifyDiagnostics();
}
[Fact]
public void LocalScope_11()
{
var source =
@"class Program
{
static void Main()
{
S s0 = default;
scoped ref S r0 = ref s0;
{
scoped ref S r1 = ref s0;
r0 = ref r1; // 1
}
{
scoped ref S r2 = ref r0;
r0 = ref r2; // 2
}
{
ref S r3 = ref s0;
r0 = ref r3;
}
{
ref S r4 = ref r0;
r0 = ref r4;
}
}
}
ref struct S { }
";
var comp = CreateCompilation(source);
comp.VerifyDiagnostics(
// (9,13): error CS8374: Cannot ref-assign 'r1' to 'r0' because 'r1' has a narrower escape scope than 'r0'.
// r0 = ref r1; // 1
Diagnostic(ErrorCode.ERR_RefAssignNarrower, "r0 = ref r1").WithArguments("r0", "r1").WithLocation(9, 13),
// (13,13): error CS8374: Cannot ref-assign 'r2' to 'r0' because 'r2' has a narrower escape scope than 'r0'.
// r0 = ref r2; // 2
Diagnostic(ErrorCode.ERR_RefAssignNarrower, "r0 = ref r2").WithArguments("r0", "r2").WithLocation(13, 13));
}
[Fact]
public void LocalScope_11_For_01()
{
var source =
@"class Program
{
static void Main()
{
S s0 = default;
scoped ref S r0 = ref s0;
for (scoped ref S r1 = ref s0;;) {
r0 = ref r1; // 1
break;
}
for (scoped ref S r2 = ref r0;;) {
r0 = ref r2; // 2
break;
}
for (ref S r3 = ref s0;;) {
r0 = ref r3;
break;
}
for (ref S r4 = ref r0;;) {
r0 = ref r4;
break;
}
}
}
ref struct S { }
";
var comp = CreateCompilation(source);
comp.VerifyDiagnostics(
// (8,13): error CS8374: Cannot ref-assign 'r1' to 'r0' because 'r1' has a narrower escape scope than 'r0'.
// r0 = ref r1; // 1
Diagnostic(ErrorCode.ERR_RefAssignNarrower, "r0 = ref r1").WithArguments("r0", "r1").WithLocation(8, 13),
// (12,13): error CS8374: Cannot ref-assign 'r2' to 'r0' because 'r2' has a narrower escape scope than 'r0'.
// r0 = ref r2; // 2
Diagnostic(ErrorCode.ERR_RefAssignNarrower, "r0 = ref r2").WithArguments("r0", "r2").WithLocation(12, 13));
}
[Fact]
public void LocalScope_11_For_02()
{
var source =
@"class Program
{
static void Main()
{
S s0 = default;
for (scoped ref S r0 = ref s0;;)
{
scoped ref S r1 = ref s0;
r0 = ref r1; // 1
scoped ref S r2 = ref r0;
r0 = ref r2; // 2
ref S r3 = ref s0;
r0 = ref r3;
ref S r4 = ref r0;
r0 = ref r4;
break;
}
}
}
ref struct S { }
";
var comp = CreateCompilation(source);
comp.VerifyDiagnostics(
// (9,13): error CS8374: Cannot ref-assign 'r1' to 'r0' because 'r1' has a narrower escape scope than 'r0'.
// r0 = ref r1; // 1
Diagnostic(ErrorCode.ERR_RefAssignNarrower, "r0 = ref r1").WithArguments("r0", "r1").WithLocation(9, 13),
// (12,13): error CS8374: Cannot ref-assign 'r2' to 'r0' because 'r2' has a narrower escape scope than 'r0'.
// r0 = ref r2; // 2
Diagnostic(ErrorCode.ERR_RefAssignNarrower, "r0 = ref r2").WithArguments("r0", "r2").WithLocation(12, 13)
);
}
[Fact]
public void LocalScope_12()
{
var source =
@"class Program
{
static void Main()
{
int i0 = 0;
S s0 = new S(ref i0);
{
int i1 = 1;
S s1 = new S(ref i1);
s0 = s1; // 1
}
{
scoped S s2 = s0;
s0 = s2; // 2
}
{
S s3 = s0;
s0 = s3;
}
}
}
ref struct S
{
public S(ref int i) { }
}
";
var comp = CreateCompilation(source);
comp.VerifyDiagnostics(
// (10,18): error CS8352: Cannot use variable 's1' in this context because it may expose referenced variables outside of their declaration scope
// s0 = s1; // 1
Diagnostic(ErrorCode.ERR_EscapeVariable, "s1").WithArguments("s1").WithLocation(10, 18),
// (14,18): error CS8352: Cannot use variable 's2' in this context because it may expose referenced variables outside of their declaration scope
// s0 = s2; // 2
Diagnostic(ErrorCode.ERR_EscapeVariable, "s2").WithArguments("s2").WithLocation(14, 18));
}
[Fact]
public void LocalScope_12_For_01()
{
var source =
@"class Program
{
static void Main()
{
int i0 = 0;
S s0 = new S(ref i0);
{
int i1 = 1;
for (S s1 = new S(ref i1);;) {
s0 = s1; // 1
break;
}
}
for (scoped S s2 = s0;;) {
s0 = s2; // 2
break;
}
for (S s3 = s0;;) {
s0 = s3;
break;
}
}
}
ref struct S
{
public S(ref int i) { }
}
";
var comp = CreateCompilation(source);
comp.VerifyDiagnostics(
// (10,22): error CS8352: Cannot use variable 's1' in this context because it may expose referenced variables outside of their declaration scope
// s0 = s1; // 1
Diagnostic(ErrorCode.ERR_EscapeVariable, "s1").WithArguments("s1").WithLocation(10, 22),
// (15,18): error CS8352: Cannot use variable 's2' in this context because it may expose referenced variables outside of their declaration scope
// s0 = s2; // 2
Diagnostic(ErrorCode.ERR_EscapeVariable, "s2").WithArguments("s2").WithLocation(15, 18)
);
}
[Fact]
public void LocalScope_12_For_02()
{
var source =
@"class Program
{
static void Main()
{
int i0 = 0;
for (S s0 = new S(ref i0);;)
{
int i1 = 1;
S s1 = new S(ref i1);
s0 = s1; // 1
scoped S s2 = s0;
s0 = s2; // 2
S s3 = s0;
s0 = s3;
break;
}
}
}
ref struct S
{
public S(ref int i) { }
}
";
var comp = CreateCompilation(source);
comp.VerifyDiagnostics(
// (10,18): error CS8352: Cannot use variable 's1' in this context because it may expose referenced variables outside of their declaration scope
// s0 = s1; // 1
Diagnostic(ErrorCode.ERR_EscapeVariable, "s1").WithArguments("s1").WithLocation(10, 18),
// (13,18): error CS8352: Cannot use variable 's2' in this context because it may expose referenced variables outside of their declaration scope
// s0 = s2; // 2
Diagnostic(ErrorCode.ERR_EscapeVariable, "s2").WithArguments("s2").WithLocation(13, 18)
);
}
[Fact]
public void LocalScope_12_Deconstruct()
{
var source =
@"class Program
{
static void Main()
{
int i0 = 0;
S s0 = new S(ref i0);
{
int i1 = 1;
(S s1, var a) = new S(ref i1);
s0 = s1;
}
{
(scoped S s2, var b) = s0;
s0 = s2;
}
{
(S s3, var c) = s0;
s0 = s3;
}
{
int i1 = 1;
S s11;
int d;
(s11, d) = new S(ref i1);
s0 = s11;
}
{
scoped S s21;
int e;
(s21, e) = s0;
s0 = s21;
}
{
S s31;
int f;
(s31, f) = s0;
s0 = s31;
}
}
}
ref struct S
{
public S(ref int i) { }
public void Deconstruct(out S x, out int y) => throw null;
}
";
var comp = CreateCompilation(source);
comp.VerifyDiagnostics(
// (10,18): error CS8352: Cannot use variable 's1' in this context because it may expose referenced variables outside of their declaration scope
// s0 = s1;
Diagnostic(ErrorCode.ERR_EscapeVariable, "s1").WithArguments("s1").WithLocation(10, 18),
// (14,18): error CS8352: Cannot use variable 's2' in this context because it may expose referenced variables outside of their declaration scope
// s0 = s2;
Diagnostic(ErrorCode.ERR_EscapeVariable, "s2").WithArguments("s2").WithLocation(14, 18),
// (24,13): error CS8352: Cannot use variable '(s11, d) = new S(ref i1)' in this context because it may expose referenced variables outside of their declaration scope
// (s11, d) = new S(ref i1);
Diagnostic(ErrorCode.ERR_EscapeVariable, "(s11, d) = new S(ref i1)").WithArguments("(s11, d) = new S(ref i1)").WithLocation(24, 13),
// (24,24): error CS8350: This combination of arguments to 'S.Deconstruct(out S, out int)' is disallowed because it may expose variables referenced by parameter 'this' outside of their declaration scope
// (s11, d) = new S(ref i1);
Diagnostic(ErrorCode.ERR_CallArgMixing, "new S(ref i1)").WithArguments("S.Deconstruct(out S, out int)", "this").WithLocation(24, 24),
// (31,18): error CS8352: Cannot use variable 's21' in this context because it may expose referenced variables outside of their declaration scope
// s0 = s21;
Diagnostic(ErrorCode.ERR_EscapeVariable, "s21").WithArguments("s21").WithLocation(31, 18),
// (36,13): error CS8352: Cannot use variable '(s31, f) = s0' in this context because it may expose referenced variables outside of their declaration scope
// (s31, f) = s0;
Diagnostic(ErrorCode.ERR_EscapeVariable, "(s31, f) = s0").WithArguments("(s31, f) = s0").WithLocation(36, 13),
// (36,24): error CS8350: This combination of arguments to 'S.Deconstruct(out S, out int)' is disallowed because it may expose variables referenced by parameter 'this' outside of their declaration scope
// (s31, f) = s0;
Diagnostic(ErrorCode.ERR_CallArgMixing, "s0").WithArguments("S.Deconstruct(out S, out int)", "this").WithLocation(36, 24)
);
}
[Fact]
public void LocalScope_12_OutVar()
{
var source =
@"class Program
{
static void Main()
{
int i0 = 0;
S s0 = new S(ref i0);
{
int i1 = 1;
(new S(ref i1)).M(out S s1);
s0 = s1;
}
{
s0.M(out scoped S s2);
s0 = s2;
}
{
s0.M(out S s3);
s0 = s3;
}
{
scoped S s21;
s0.M(out s21);
s0 = s21;
}
{
int i1 = 1;
(new S(ref i1)).M(out scoped S s4);
s0 = s4;
}
{
int i1 = 1;
(new S(ref i1)).M(out var s5);
s0 = s5;
}
{
int i1 = 1;
(new S(ref i1)).M(out scoped var s7);
s0 = s7;
}
}
}
ref struct S
{
public S(ref int i) { }
public void M(out S x) => throw null;
}
";
var comp = CreateCompilation(source);
comp.VerifyDiagnostics(
// (10,18): error CS8352: Cannot use variable 's1' in this context because it may expose referenced variables outside of their declaration scope
// s0 = s1;
Diagnostic(ErrorCode.ERR_EscapeVariable, "s1").WithArguments("s1").WithLocation(10, 18),
// (14,18): error CS8352: Cannot use variable 's2' in this context because it may expose referenced variables outside of their declaration scope
// s0 = s2;
Diagnostic(ErrorCode.ERR_EscapeVariable, "s2").WithArguments("s2").WithLocation(14, 18),
// (23,18): error CS8352: Cannot use variable 's21' in this context because it may expose referenced variables outside of their declaration scope
// s0 = s21;
Diagnostic(ErrorCode.ERR_EscapeVariable, "s21").WithArguments("s21").WithLocation(23, 18),
// (29,18): error CS8352: Cannot use variable 's4' in this context because it may expose referenced variables outside of their declaration scope
// s0 = s4;
Diagnostic(ErrorCode.ERR_EscapeVariable, "s4").WithArguments("s4").WithLocation(29, 18),
// (34,18): error CS8352: Cannot use variable 's5' in this context because it may expose referenced variables outside of their declaration scope
// s0 = s5;
Diagnostic(ErrorCode.ERR_EscapeVariable, "s5").WithArguments("s5").WithLocation(34, 18),
// (39,18): error CS8352: Cannot use variable 's7' in this context because it may expose referenced variables outside of their declaration scope
// s0 = s7;
Diagnostic(ErrorCode.ERR_EscapeVariable, "s7").WithArguments("s7").WithLocation(39, 18)
);
}
[Fact]
public void LocalScope_13()
{
var source =
@"#pragma warning disable 219
ref struct R { }
class Program
{
static void F(ref R r)
{
scoped ref R r2 = ref r, r5 = ref r;
}
}";
var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10);
comp.VerifyEmitDiagnostics(
// (7,9): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater.
// scoped ref R r2 = ref r, r5 = ref r;
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "scoped").WithArguments("ref fields", "11.0").WithLocation(7, 9)
);
verify(comp, useUpdatedEscapeRules: false);
comp = CreateCompilation(source);
comp.VerifyEmitDiagnostics();
verify(comp, useUpdatedEscapeRules: true);
static void verify(CSharpCompilation comp, bool useUpdatedEscapeRules)
{
var tree = comp.SyntaxTrees[0];
var model = comp.GetSemanticModel(tree);
var decls = tree.GetRoot().DescendantNodes().OfType<VariableDeclaratorSyntax>().ToArray();
var locals = decls.Select(d => model.GetDeclaredSymbol(d).GetSymbol<LocalSymbol>()).ToArray();
VerifyLocalSymbol(locals[0], "scoped ref R r2", RefKind.Ref, ScopedKind.ScopedRef);
VerifyLocalSymbol(locals[1], "scoped ref R r5", RefKind.Ref, ScopedKind.ScopedRef);
var type = ((VariableDeclarationSyntax)decls[0].Parent).Type;
Assert.Null(model.GetTypeInfo(type).Type);
Assert.Equal("R", model.GetSymbolInfo(type.SkipScoped(out _).SkipRef()).Symbol.ToTestDisplayString());
}
}
[Fact]
public void LocalScope_13_For()
{
var source =
@"#pragma warning disable 219
ref struct R { }
class Program
{
static void F(ref R r)
{
for (scoped ref R r2 = ref r, r5 = ref r;;) break;
}
}";
var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10);
comp.VerifyEmitDiagnostics(
// (7,14): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater.
// for (scoped ref R r2 = ref r, r5 = ref r;;) break;
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "scoped").WithArguments("ref fields", "11.0").WithLocation(7, 14)
);
verify(comp, useUpdatedEscapeRules: false);
comp = CreateCompilation(source);
comp.VerifyEmitDiagnostics();
verify(comp, useUpdatedEscapeRules: true);
static void verify(CSharpCompilation comp, bool useUpdatedEscapeRules)
{
var tree = comp.SyntaxTrees[0];
var model = comp.GetSemanticModel(tree);
var decls = tree.GetRoot().DescendantNodes().OfType<VariableDeclaratorSyntax>().ToArray();
var locals = decls.Select(d => model.GetDeclaredSymbol(d).GetSymbol<LocalSymbol>()).ToArray();
VerifyLocalSymbol(locals[0], "scoped ref R r2", RefKind.Ref, ScopedKind.ScopedRef);
VerifyLocalSymbol(locals[1], "scoped ref R r5", RefKind.Ref, ScopedKind.ScopedRef);
var type = ((VariableDeclarationSyntax)decls[0].Parent).Type;
Assert.Null(model.GetTypeInfo(type).Type);
Assert.Equal("R", model.GetSymbolInfo(type.SkipScoped(out _).SkipRef()).Symbol.ToTestDisplayString());
}
}
[Fact]
public void ScopedRefAndRefStructOnly_06_For()
{
var source =
@"#pragma warning disable CS0219 // The variable is assigned but its value is never used
struct S<T> { }
class Program
{
static void Main()
{
for (scoped var y1 = new S<int>();;) break;
var y2 = new S<int>();
for (scoped ref var y3 = ref y2;;) break;
for (scoped S<int> y4 = new S<int>(), y5 = new S<int>();;) break;
}
}";
var comp = CreateCompilation(source);
comp.VerifyDiagnostics(
// (7,21): error CS9048: The 'scoped' modifier can be used for refs and ref struct values only.
// for (scoped var y1 = new S<int>();;) break; // 2
Diagnostic(ErrorCode.ERR_ScopedRefAndRefStructOnly, "var").WithLocation(7, 21),
// (10,21): error CS9048: The 'scoped' modifier can be used for refs and ref struct values only.
// for (scoped S<int> y4 = new S<int>(), y5 = new S<int>();;) break;
Diagnostic(ErrorCode.ERR_ScopedRefAndRefStructOnly, "S<int>").WithLocation(10, 21),
// (10,21): error CS9048: The 'scoped' modifier can be used for refs and ref struct values only.
// for (scoped S<int> y4 = new S<int>(), y5 = new S<int>();;) break;
Diagnostic(ErrorCode.ERR_ScopedRefAndRefStructOnly, "S<int>").WithLocation(10, 21)
);
}
[Fact]
public void ScopedRefAndRefStructOnly_06_Deconstruct()
{
var source =
@"#pragma warning disable CS0219 // The variable is assigned but its value is never used
struct S<T> { }
class Program
{
static void Main()
{
(scoped var y1, var a) = (new S<int>(), 0);
(var y2, var b) = (new S<int>(), 1);
(scoped S<int> y3, var c) = (new S<int>(), 0);
(S<int> y4, var d) = (new S<int>(), 1);
}
}";
var comp = CreateCompilation(source);
comp.VerifyDiagnostics(
// (7,17): error CS9048: The 'scoped' modifier can be used for refs and ref struct values only.
// (scoped var y1, var a) = (new S<int>(), 0);
Diagnostic(ErrorCode.ERR_ScopedRefAndRefStructOnly, "var").WithLocation(7, 17),
// (9,17): error CS9048: The 'scoped' modifier can be used for refs and ref struct values only.
// (scoped S<int> y3, var c) = (new S<int>(), 0);
Diagnostic(ErrorCode.ERR_ScopedRefAndRefStructOnly, "S<int>").WithLocation(9, 17)
);
}
[Fact]
public void ScopedRefAndRefStructOnly_06_OutVar()
{
var source =
@"#pragma warning disable CS0219 // The variable is assigned but its value is never used
struct S<T> { }
class Program
{
static void Main()
{
M(out scoped var y1);
M(out var y2);
M(out scoped S<int> y3);
M(out S<int> y4);
}
static void M(out S<int> x) => throw null;
}";
var comp = CreateCompilation(source);
comp.VerifyDiagnostics(
// (7,22): error CS9048: The 'scoped' modifier can be used for refs and ref struct values only.
// M(out scoped var y1);
Diagnostic(ErrorCode.ERR_ScopedRefAndRefStructOnly, "var").WithLocation(7, 22),
// (9,22): error CS9048: The 'scoped' modifier can be used for refs and ref struct values only.
// M(out scoped S<int> y3);
Diagnostic(ErrorCode.ERR_ScopedRefAndRefStructOnly, "S<int>").WithLocation(9, 22)
);
}
[Fact]
public void LocalScopeAndInitializer_01()
{
var source =
@"ref struct R { }
class Program
{
static void Values(R r1, scoped R r2)
{
R r11 = r1;
R r12 = r2;
scoped R r21 = r1;
scoped R r22 = r2;
}
static void Refs(ref R r1, scoped ref R r2)
{
ref R r31 = ref r1;
ref R r32 = ref r2;
scoped ref R r41 = ref r1;
scoped ref R r42 = ref r2;
}
}";
var comp = CreateCompilation(source);
comp.VerifyEmitDiagnostics();
var tree = comp.SyntaxTrees[0];
var model = comp.GetSemanticModel(tree);
var decls = tree.GetRoot().DescendantNodes().OfType<VariableDeclaratorSyntax>().ToArray();
var locals = decls.Select(d => model.GetDeclaredSymbol(d).GetSymbol<LocalSymbol>()).ToArray();
VerifyLocalSymbol(locals[0], "R r11", RefKind.None, ScopedKind.None);
VerifyLocalSymbol(locals[1], "R r12", RefKind.None, ScopedKind.None);
VerifyLocalSymbol(locals[2], "scoped R r21", RefKind.None, ScopedKind.ScopedValue);
VerifyLocalSymbol(locals[3], "scoped R r22", RefKind.None, ScopedKind.ScopedValue);
VerifyLocalSymbol(locals[4], "ref R r31", RefKind.Ref, ScopedKind.None);
VerifyLocalSymbol(locals[5], "ref R r32", RefKind.Ref, ScopedKind.None);
VerifyLocalSymbol(locals[6], "scoped ref R r41", RefKind.Ref, ScopedKind.ScopedRef);
VerifyLocalSymbol(locals[7], "scoped ref R r42", RefKind.Ref, ScopedKind.ScopedRef);
}
[Fact]
public void LocalScope_01_Foreach_01()
{
var source =
@"#pragma warning disable 219
ref struct R { }
class Program
{
static void F(ref R r)
{
foreach (scoped R r1 in new Enumerable1()) break;
foreach (scoped ref R r2 in new Enumerable2(ref r)) break;
foreach (scoped ref readonly R r5 in new Enumerable2(ref r)) break;
}
}
class Enumerable1
{
public Enumerator1 GetEnumerator() => default;
}
class Enumerator1
{
public R Current => default;
public bool MoveNext() => false;
}
class Enumerable2
{
public Enumerable2(ref R x) {}
public Enumerator2 GetEnumerator() => default;
}
class Enumerator2
{
public ref R Current => throw null;
public bool MoveNext() => false;
}
";
var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10);
comp.VerifyEmitDiagnostics(
// (7,18): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater.
// foreach (scoped R r1 in new Enumerable1()) break;
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "scoped").WithArguments("ref fields", "11.0").WithLocation(7, 18),
// (8,18): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater.
// foreach (scoped ref R r2 in new Enumerable2(ref r)) break;
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "scoped").WithArguments("ref fields", "11.0").WithLocation(8, 18),
// (9,18): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater.
// foreach (scoped ref readonly R r5 in new Enumerable2(ref r)) break;
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "scoped").WithArguments("ref fields", "11.0").WithLocation(9, 18)
);
verify(comp);
comp = CreateCompilation(source);
comp.VerifyEmitDiagnostics();
verify(comp);
static void verify(CSharpCompilation comp)
{
var tree = comp.SyntaxTrees[0];
var model = comp.GetSemanticModel(tree);
var decls = tree.GetRoot().DescendantNodes().OfType<ForEachStatementSyntax>().ToArray();
var locals = decls.Select(d => model.GetDeclaredSymbol(d).GetSymbol<LocalSymbol>()).ToArray();
VerifyLocalSymbol(locals[0], "scoped R r1", RefKind.None, ScopedKind.ScopedValue);
VerifyLocalSymbol(locals[1], "scoped ref R r2", RefKind.Ref, ScopedKind.ScopedRef);
VerifyLocalSymbol(locals[2], "scoped ref readonly R r5", RefKind.RefReadOnly, ScopedKind.ScopedRef);
foreach (var decl in decls)
{
var type = decl.Type;
Assert.True(SyntaxFacts.IsInTypeOnlyContext(type));
Assert.True(SyntaxFacts.IsInTypeOnlyContext(type.SkipScoped(out _)));
Assert.True(SyntaxFacts.IsInTypeOnlyContext(type.SkipScoped(out _).SkipRef()));
Assert.Null(model.GetSymbolInfo(type).Symbol);
Assert.Null(model.GetTypeInfo(type).Type);
type = type.SkipScoped(out _);
if (type is RefTypeSyntax refType)
{
Assert.Null(model.GetSymbolInfo(type).Symbol);
Assert.Null(model.GetTypeInfo(type).Type);
type = refType.Type;
}
Assert.Equal("R", model.GetSymbolInfo(type).Symbol.ToTestDisplayString());
Assert.Equal("R", model.GetTypeInfo(type).Type.ToTestDisplayString());
}
}
}
[Theory]
[InlineData(LanguageVersion.CSharp10)]
[InlineData(LanguageVersion.CSharp11)]
public void LocalScope_01_Foreach_02(LanguageVersion languageVersion)
{
var source =
@"#pragma warning disable 219
ref struct R { }
class Program
{
static void F(ref R r)
{
foreach (var _ in new Enumerable1()) break;
foreach (R _ in new Enumerable1()) break;
foreach (ref var _ in new Enumerable2(ref r)) break;
foreach (ref readonly var _ in new Enumerable2(ref r)) break;
foreach (ref R _ in new Enumerable2(ref r)) break;
}
}
class Enumerable1
{
public Enumerator1 GetEnumerator() => default;
}
class Enumerator1
{
public R Current => default;
public bool MoveNext() => false;
}
class Enumerable2
{
public Enumerable2(ref R x) {}
public Enumerator2 GetEnumerator() => default;
}
class Enumerator2
{
public ref R Current => throw null;
public bool MoveNext() => false;
}
";
var comp = CreateCompilation(source, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion));
comp.VerifyEmitDiagnostics();
}
[Fact]
public void LocalScope_01_Foreach_Deconstruction_01()
{
var source =
@"#pragma warning disable 219
class Program
{
static void F(ref R r)
{
foreach ((scoped R r1, scoped var _) in new Enumerable1()) break;
foreach ((scoped ref R r2, scoped ref var _) in new Enumerable2(ref r)) break;
foreach ((scoped ref readonly R r5, scoped ref readonly var _) in new Enumerable2(ref r)) break;
foreach ((scoped var r11, scoped R _) in new Enumerable1()) break;
foreach ((scoped ref var r21, scoped ref R _) in new Enumerable2(ref r)) break;
foreach ((scoped ref readonly var r51, scoped ref readonly R _) in new Enumerable2(ref r)) break;
}
}
ref struct R
{
public void Deconstruct(out R x, out R y) => throw null;
}
class Enumerable1
{
public Enumerator1 GetEnumerator() => default;
}
class Enumerator1
{
public R Current => default;
public bool MoveNext() => false;
}
class Enumerable2
{
public Enumerable2(ref R x) {}
public Enumerator2 GetEnumerator() => default;
}
class Enumerator2
{
public ref R Current => throw null;
public bool MoveNext() => false;
}
";
var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10);
comp.VerifyEmitDiagnostics(
// (7,19): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater.
// foreach ((scoped R r1, scoped var _) in new Enumerable1()) break;
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "scoped").WithArguments("ref fields", "11.0").WithLocation(7, 19),
// (7,32): error CS9061: The 'scoped' modifier cannot be used with discard.
// foreach ((scoped R r1, scoped var _) in new Enumerable1()) break;
Diagnostic(ErrorCode.ERR_ScopedDiscard, "scoped").WithLocation(7, 32),
// (8,19): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater.
// foreach ((scoped ref R r2, scoped ref var _) in new Enumerable2(ref r)) break;
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "scoped").WithArguments("ref fields", "11.0").WithLocation(8, 19),
// (8,26): error CS9072: A deconstruction variable cannot be declared as a ref local
// foreach ((scoped ref R r2, scoped ref var _) in new Enumerable2(ref r)) break;
Diagnostic(ErrorCode.ERR_DeconstructVariableCannotBeByRef, "ref").WithLocation(8, 26),
// (8,36): error CS9061: The 'scoped' modifier cannot be used with discard.
// foreach ((scoped ref R r2, scoped ref var _) in new Enumerable2(ref r)) break;
Diagnostic(ErrorCode.ERR_ScopedDiscard, "scoped").WithLocation(8, 36),
// (8,43): error CS9072: A deconstruction variable cannot be declared as a ref local
// foreach ((scoped ref R r2, scoped ref var _) in new Enumerable2(ref r)) break;
Diagnostic(ErrorCode.ERR_DeconstructVariableCannotBeByRef, "ref").WithLocation(8, 43),
// (9,19): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater.
// foreach ((scoped ref readonly R r5, scoped ref readonly var _) in new Enumerable2(ref r)) break;
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "scoped").WithArguments("ref fields", "11.0").WithLocation(9, 19),
// (9,26): error CS9072: A deconstruction variable cannot be declared as a ref local
// foreach ((scoped ref readonly R r5, scoped ref readonly var _) in new Enumerable2(ref r)) break;
Diagnostic(ErrorCode.ERR_DeconstructVariableCannotBeByRef, "ref").WithLocation(9, 26),
// (9,45): error CS9061: The 'scoped' modifier cannot be used with discard.
// foreach ((scoped ref readonly R r5, scoped ref readonly var _) in new Enumerable2(ref r)) break;
Diagnostic(ErrorCode.ERR_ScopedDiscard, "scoped").WithLocation(9, 45),
// (9,52): error CS9072: A deconstruction variable cannot be declared as a ref local
// foreach ((scoped ref readonly R r5, scoped ref readonly var _) in new Enumerable2(ref r)) break;
Diagnostic(ErrorCode.ERR_DeconstructVariableCannotBeByRef, "ref").WithLocation(9, 52),
// (11,19): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater.
// foreach ((scoped var r11, scoped R _) in new Enumerable1()) break;
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "scoped").WithArguments("ref fields", "11.0").WithLocation(11, 19),
// (11,35): error CS9061: The 'scoped' modifier cannot be used with discard.
// foreach ((scoped var r11, scoped R _) in new Enumerable1()) break;
Diagnostic(ErrorCode.ERR_ScopedDiscard, "scoped").WithLocation(11, 35),
// (12,19): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater.
// foreach ((scoped ref var r21, scoped ref R _) in new Enumerable2(ref r)) break;
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "scoped").WithArguments("ref fields", "11.0").WithLocation(12, 19),
// (12,26): error CS9072: A deconstruction variable cannot be declared as a ref local
// foreach ((scoped ref var r21, scoped ref R _) in new Enumerable2(ref r)) break;
Diagnostic(ErrorCode.ERR_DeconstructVariableCannotBeByRef, "ref").WithLocation(12, 26),
// (12,39): error CS9061: The 'scoped' modifier cannot be used with discard.
// foreach ((scoped ref var r21, scoped ref R _) in new Enumerable2(ref r)) break;
Diagnostic(ErrorCode.ERR_ScopedDiscard, "scoped").WithLocation(12, 39),
// (12,46): error CS9072: A deconstruction variable cannot be declared as a ref local
// foreach ((scoped ref var r21, scoped ref R _) in new Enumerable2(ref r)) break;
Diagnostic(ErrorCode.ERR_DeconstructVariableCannotBeByRef, "ref").WithLocation(12, 46),
// (13,19): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater.
// foreach ((scoped ref readonly var r51, scoped ref readonly R _) in new Enumerable2(ref r)) break;
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "scoped").WithArguments("ref fields", "11.0").WithLocation(13, 19),
// (13,26): error CS9072: A deconstruction variable cannot be declared as a ref local
// foreach ((scoped ref readonly var r51, scoped ref readonly R _) in new Enumerable2(ref r)) break;
Diagnostic(ErrorCode.ERR_DeconstructVariableCannotBeByRef, "ref").WithLocation(13, 26),
// (13,48): error CS9061: The 'scoped' modifier cannot be used with discard.
// foreach ((scoped ref readonly var r51, scoped ref readonly R _) in new Enumerable2(ref r)) break;
Diagnostic(ErrorCode.ERR_ScopedDiscard, "scoped").WithLocation(13, 48),
// (13,55): error CS9072: A deconstruction variable cannot be declared as a ref local
// foreach ((scoped ref readonly var r51, scoped ref readonly R _) in new Enumerable2(ref r)) break;
Diagnostic(ErrorCode.ERR_DeconstructVariableCannotBeByRef, "ref").WithLocation(13, 55)
);
verify(comp);
comp = CreateCompilation(source);
comp.VerifyEmitDiagnostics(
// (7,32): error CS9061: The 'scoped' modifier cannot be used with discard.
// foreach ((scoped R r1, scoped var _) in new Enumerable1()) break;
Diagnostic(ErrorCode.ERR_ScopedDiscard, "scoped").WithLocation(7, 32),
// (8,26): error CS9072: A deconstruction variable cannot be declared as a ref local
// foreach ((scoped ref R r2, scoped ref var _) in new Enumerable2(ref r)) break;
Diagnostic(ErrorCode.ERR_DeconstructVariableCannotBeByRef, "ref").WithLocation(8, 26),
// (8,36): error CS9061: The 'scoped' modifier cannot be used with discard.
// foreach ((scoped ref R r2, scoped ref var _) in new Enumerable2(ref r)) break;
Diagnostic(ErrorCode.ERR_ScopedDiscard, "scoped").WithLocation(8, 36),
// (8,43): error CS9072: A deconstruction variable cannot be declared as a ref local
// foreach ((scoped ref R r2, scoped ref var _) in new Enumerable2(ref r)) break;
Diagnostic(ErrorCode.ERR_DeconstructVariableCannotBeByRef, "ref").WithLocation(8, 43),
// (9,26): error CS9072: A deconstruction variable cannot be declared as a ref local
// foreach ((scoped ref readonly R r5, scoped ref readonly var _) in new Enumerable2(ref r)) break;
Diagnostic(ErrorCode.ERR_DeconstructVariableCannotBeByRef, "ref").WithLocation(9, 26),
// (9,45): error CS9061: The 'scoped' modifier cannot be used with discard.
// foreach ((scoped ref readonly R r5, scoped ref readonly var _) in new Enumerable2(ref r)) break;
Diagnostic(ErrorCode.ERR_ScopedDiscard, "scoped").WithLocation(9, 45),
// (9,52): error CS9072: A deconstruction variable cannot be declared as a ref local
// foreach ((scoped ref readonly R r5, scoped ref readonly var _) in new Enumerable2(ref r)) break;
Diagnostic(ErrorCode.ERR_DeconstructVariableCannotBeByRef, "ref").WithLocation(9, 52),
// (11,35): error CS9061: The 'scoped' modifier cannot be used with discard.
// foreach ((scoped var r11, scoped R _) in new Enumerable1()) break;
Diagnostic(ErrorCode.ERR_ScopedDiscard, "scoped").WithLocation(11, 35),
// (12,26): error CS9072: A deconstruction variable cannot be declared as a ref local
// foreach ((scoped ref var r21, scoped ref R _) in new Enumerable2(ref r)) break;
Diagnostic(ErrorCode.ERR_DeconstructVariableCannotBeByRef, "ref").WithLocation(12, 26),
// (12,39): error CS9061: The 'scoped' modifier cannot be used with discard.
// foreach ((scoped ref var r21, scoped ref R _) in new Enumerable2(ref r)) break;
Diagnostic(ErrorCode.ERR_ScopedDiscard, "scoped").WithLocation(12, 39),
// (12,46): error CS9072: A deconstruction variable cannot be declared as a ref local
// foreach ((scoped ref var r21, scoped ref R _) in new Enumerable2(ref r)) break;
Diagnostic(ErrorCode.ERR_DeconstructVariableCannotBeByRef, "ref").WithLocation(12, 46),
// (13,26): error CS9072: A deconstruction variable cannot be declared as a ref local
// foreach ((scoped ref readonly var r51, scoped ref readonly R _) in new Enumerable2(ref r)) break;
Diagnostic(ErrorCode.ERR_DeconstructVariableCannotBeByRef, "ref").WithLocation(13, 26),
// (13,48): error CS9061: The 'scoped' modifier cannot be used with discard.
// foreach ((scoped ref readonly var r51, scoped ref readonly R _) in new Enumerable2(ref r)) break;
Diagnostic(ErrorCode.ERR_ScopedDiscard, "scoped").WithLocation(13, 48),
// (13,55): error CS9072: A deconstruction variable cannot be declared as a ref local
// foreach ((scoped ref readonly var r51, scoped ref readonly R _) in new Enumerable2(ref r)) break;
Diagnostic(ErrorCode.ERR_DeconstructVariableCannotBeByRef, "ref").WithLocation(13, 55)
);
verify(comp);
static void verify(CSharpCompilation comp)
{
var tree = comp.SyntaxTrees[0];
var model = comp.GetSemanticModel(tree);
var decls = tree.GetRoot().DescendantNodes().OfType<SingleVariableDesignationSyntax>().ToArray();
var locals = decls.Select(d => model.GetDeclaredSymbol(d).GetSymbol<LocalSymbol>()).ToArray();
VerifyLocalSymbol(locals[0], "scoped R r1", RefKind.None, ScopedKind.ScopedValue);
VerifyLocalSymbol(locals[1], "scoped R r2", RefKind.None, ScopedKind.ScopedValue);
VerifyLocalSymbol(locals[2], "scoped R r5", RefKind.None, ScopedKind.ScopedValue);
VerifyLocalSymbol(locals[3], "scoped R r11", RefKind.None, ScopedKind.ScopedValue);
VerifyLocalSymbol(locals[4], "scoped R r21", RefKind.None, ScopedKind.ScopedValue);
VerifyLocalSymbol(locals[5], "scoped R r51", RefKind.None, ScopedKind.ScopedValue);
foreach (var decl in decls)
{
var type = ((DeclarationExpressionSyntax)decl.Parent).Type;
Assert.Null(model.GetSymbolInfo(type).Symbol);
Assert.Null(model.GetTypeInfo(type).Type);
type = type.SkipScoped(out _);
if (type is RefTypeSyntax refType)
{
Assert.Null(model.GetSymbolInfo(type).Symbol);
Assert.Null(model.GetTypeInfo(type).Type);
type = refType.Type;
}
Assert.Equal("R", model.GetSymbolInfo(type).Symbol.ToTestDisplayString());
Assert.Equal("R", model.GetTypeInfo(type).Type.ToTestDisplayString());
}
var discard = tree.GetRoot().DescendantNodes().OfType<DiscardDesignationSyntax>().ToArray();
Assert.Equal(6, discard.Length);
foreach (var decl in discard)
{
Assert.Null(model.GetDeclaredSymbol(decl));
Assert.Null(model.GetSymbolInfo(decl).Symbol);
Assert.Null(model.GetTypeInfo(decl).Type);
var type = ((DeclarationExpressionSyntax)decl.Parent).Type;
Assert.Null(model.GetSymbolInfo(type).Symbol);
Assert.Null(model.GetTypeInfo(type).Type);
type = type.SkipScoped(out _);
if (type is RefTypeSyntax refType)
{
Assert.Null(model.GetSymbolInfo(type).Symbol);
Assert.Null(model.GetTypeInfo(type).Type);
type = refType.Type;
}
Assert.Equal("R", model.GetSymbolInfo(type).Symbol.ToTestDisplayString());
Assert.Equal("R", model.GetTypeInfo(type).Type.ToTestDisplayString());
}
}
}
[Theory]
[InlineData(LanguageVersion.CSharp10)]
[InlineData(LanguageVersion.CSharp11)]
public void LocalScope_01_Foreach_Deconstruction_02(LanguageVersion languageVersion)
{
var source =
@"#pragma warning disable 219
class Program
{
static void F0(ref R r)
{
foreach ((R r0, _) in new Enumerable1()) break;
foreach ((R r1, var _) in new Enumerable1()) break;
foreach ((ref R r2, ref var _) in new Enumerable2(ref r)) break;
foreach ((ref readonly R r5, ref readonly var _) in new Enumerable2(ref r)) break;
foreach ((var r11, R _) in new Enumerable1()) break;
foreach ((ref var r21, ref R _) in new Enumerable2(ref r)) break;
foreach ((ref readonly var r51, ref readonly R _) in new Enumerable2(ref r)) break;
}
static void F1()
{
var e1 = new Enumerable1().GetEnumerator();
e1.MoveNext();
e1.Current.Deconstruct(out R r0, out _);
e1.Current.Deconstruct(out R r1, out var _);
e1.Current.Deconstruct(out var r11, out R _);
}
}
ref struct R
{
public void Deconstruct(out R x, out R y) => throw null;
}
class Enumerable1
{
public Enumerator1 GetEnumerator() => default;
}
class Enumerator1
{
public R Current => default;
public bool MoveNext() => false;
}
class Enumerable2
{
public Enumerable2(ref R x) {}
public Enumerator2 GetEnumerator() => default;
}
class Enumerator2
{
public ref R Current => throw null;
public bool MoveNext() => false;
}
";
var comp = CreateCompilation(source, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion));
comp.VerifyEmitDiagnostics(
// (10,19): error CS9072: A deconstruction variable cannot be declared as a ref local
// foreach ((ref R r2, ref var _) in new Enumerable2(ref r)) break;
Diagnostic(ErrorCode.ERR_DeconstructVariableCannotBeByRef, "ref").WithLocation(10, 19),
// (10,29): error CS9072: A deconstruction variable cannot be declared as a ref local
// foreach ((ref R r2, ref var _) in new Enumerable2(ref r)) break;
Diagnostic(ErrorCode.ERR_DeconstructVariableCannotBeByRef, "ref").WithLocation(10, 29),
// (11,19): error CS9072: A deconstruction variable cannot be declared as a ref local
// foreach ((ref readonly R r5, ref readonly var _) in new Enumerable2(ref r)) break;
Diagnostic(ErrorCode.ERR_DeconstructVariableCannotBeByRef, "ref").WithLocation(11, 19),
// (11,38): error CS9072: A deconstruction variable cannot be declared as a ref local
// foreach ((ref readonly R r5, ref readonly var _) in new Enumerable2(ref r)) break;
Diagnostic(ErrorCode.ERR_DeconstructVariableCannotBeByRef, "ref").WithLocation(11, 38),
// (14,19): error CS9072: A deconstruction variable cannot be declared as a ref local
// foreach ((ref var r21, ref R _) in new Enumerable2(ref r)) break;
Diagnostic(ErrorCode.ERR_DeconstructVariableCannotBeByRef, "ref").WithLocation(14, 19),
// (14,32): error CS9072: A deconstruction variable cannot be declared as a ref local
// foreach ((ref var r21, ref R _) in new Enumerable2(ref r)) break;
Diagnostic(ErrorCode.ERR_DeconstructVariableCannotBeByRef, "ref").WithLocation(14, 32),
// (15,19): error CS9072: A deconstruction variable cannot be declared as a ref local
// foreach ((ref readonly var r51, ref readonly R _) in new Enumerable2(ref r)) break;
Diagnostic(ErrorCode.ERR_DeconstructVariableCannotBeByRef, "ref").WithLocation(15, 19),
// (15,41): error CS9072: A deconstruction variable cannot be declared as a ref local
// foreach ((ref readonly var r51, ref readonly R _) in new Enumerable2(ref r)) break;
Diagnostic(ErrorCode.ERR_DeconstructVariableCannotBeByRef, "ref").WithLocation(15, 41));
}
[Fact]
public void LocalScope_04_Foreach()
{
var source =
@"foreach (scoped s1 in new Enumerable1()) {
foreach (ref scoped s2 in new Enumerable2()) {break;} // 1
foreach (ref @scoped s3 in new Enumerable2()) {break;}
foreach (scoped scoped s4 in new Enumerable1()) {break;} // 2
foreach (scoped ref scoped s5 in new Enumerable2()) {break;} // 3
foreach (scoped ref @scoped s6 in new Enumerable2()) {break;} // 4
}
ref struct @scoped { } // 5
class Enumerable1
{
public Enumerator1 GetEnumerator() => default;
}
class Enumerator1
{
public @scoped Current => default;
public bool MoveNext() => false;
}
class Enumerable2
{
public Enumerator2 GetEnumerator() => default;
}
class Enumerator2
{
public ref @scoped Current => throw null;
public bool MoveNext() => false;
}
";
var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10);
comp.VerifyEmitDiagnostics(
// (4,14): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater.
// foreach (scoped scoped s4 in new Enumerable1()) {break;} // 2
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "scoped").WithArguments("ref fields", "11.0").WithLocation(4, 14),
// (5,14): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater.
// foreach (scoped ref scoped s5 in new Enumerable2()) {break;} // 3
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "scoped").WithArguments("ref fields", "11.0").WithLocation(5, 14),
// (6,14): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater.
// foreach (scoped ref @scoped s6 in new Enumerable2()) {break;} // 4
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "scoped").WithArguments("ref fields", "11.0").WithLocation(6, 14)
);
verify(comp);
comp = CreateCompilation(source);
comp.VerifyDiagnostics();
verify(comp);
static void verify(CSharpCompilation comp)
{
var tree = comp.SyntaxTrees[0];
var model = comp.GetSemanticModel(tree);
var decls = tree.GetRoot().DescendantNodes().OfType<ForEachStatementSyntax>().ToArray();
var locals = decls.Select(d => model.GetDeclaredSymbol(d).GetSymbol<LocalSymbol>()).ToArray();
VerifyLocalSymbol(locals[0], "scoped s1", RefKind.None, ScopedKind.None);
VerifyLocalSymbol(locals[1], "ref scoped s2", RefKind.Ref, ScopedKind.None);
VerifyLocalSymbol(locals[2], "ref scoped s3", RefKind.Ref, ScopedKind.None);
VerifyLocalSymbol(locals[3], "scoped scoped s4", RefKind.None, ScopedKind.ScopedValue);
VerifyLocalSymbol(locals[4], "scoped ref scoped s5", RefKind.Ref, ScopedKind.ScopedRef);
VerifyLocalSymbol(locals[5], "scoped ref scoped s6", RefKind.Ref, ScopedKind.ScopedRef);
}
}
[Theory]
[InlineData(LanguageVersion.CSharp10)]
[InlineData(LanguageVersion.CSharp11)]
public void LocalScope_05_Foreach(LanguageVersion langVersion)
{
var source =
@"foreach (bool scoped in new bool[] {}) {
}
";
var comp = CreateCompilation(source, parseOptions: TestOptions.Regular.WithLanguageVersion(langVersion));
comp.VerifyDiagnostics();
var tree = comp.SyntaxTrees[0];
var model = comp.GetSemanticModel(tree);
var decls = tree.GetRoot().DescendantNodes().OfType<ForEachStatementSyntax>().ToArray();
var locals = decls.Select(d => model.GetDeclaredSymbol(d).GetSymbol<LocalSymbol>()).ToArray();
VerifyLocalSymbol(locals[0], "System.Boolean scoped", RefKind.None, ScopedKind.None);
}
[Fact]
public void LocalScope_06_Foreach()
{
var source =
@"ref struct R<T> { }
class Program
{
static void M(R<int> r0)
{
foreach (scoped var r1 in new Enumerable1<int>()) break;
foreach (scoped ref var r3 in new Enumerable2<int>(ref r0)) break;
}
}
class Enumerable1<T>
{
public Enumerator1<T> GetEnumerator() => default;
}
class Enumerator1<T>
{
public R<T> Current => default;
public bool MoveNext() => false;
}
class Enumerable2<T>
{
public Enumerable2(ref R<T> x) {}
public Enumerator2<T> GetEnumerator() => default;
}
class Enumerator2<T>
{
public ref R<T> Current => throw null;
public bool MoveNext() => false;
}
";
var comp = CreateCompilation(source);
comp.VerifyDiagnostics();
verifyModel(comp);
comp = CreateCompilation(source, parseOptions: TestOptions.RegularDefault.WithFeature("run-nullable-analysis", "never"));
verifyModel(comp);
static void verifyModel(CSharpCompilation comp)
{
var tree = comp.SyntaxTrees[0];
var model = comp.GetSemanticModel(tree);
var decls = tree.GetRoot().DescendantNodes().OfType<ForEachStatementSyntax>().ToArray();
var locals = decls.Select(d => model.GetDeclaredSymbol(d).GetSymbol<LocalSymbol>()).ToArray();
foreach (SourceLocalSymbol local in locals)
{
Assert.True(local.IsVar);
Assert.Equal("R<System.Int32>", local.Type.ToTestDisplayString());
}
VerifyLocalSymbol(locals[0], "scoped R<System.Int32> r1", RefKind.None, ScopedKind.ScopedValue);
VerifyLocalSymbol(locals[1], "scoped ref R<System.Int32> r3", RefKind.Ref, ScopedKind.ScopedRef);
foreach (var decl in decls)
{
var type = decl.Type;
Assert.Null(model.GetSymbolInfo(type).Symbol);
Assert.Null(model.GetTypeInfo(type).Type);
type = type.SkipScoped(out _);
if (type is RefTypeSyntax refType)
{
Assert.Null(model.GetSymbolInfo(type).Symbol);
Assert.Null(model.GetTypeInfo(type).Type);
type = refType.Type;
}
Assert.Equal("R<System.Int32>", model.GetSymbolInfo(type).Symbol.ToTestDisplayString());
Assert.Equal("R<System.Int32>", model.GetTypeInfo(type).Type.ToTestDisplayString());
}
}
}
[Fact]
public void LocalScope_09_Foreach_01()
{
var source =
@"foreach (scoped s1 in new Enumerable1()) {
scoped ref @scoped s2 = ref s1;
}
ref struct @scoped { }
class Enumerable1
{
public Enumerator1 GetEnumerator() => default;
}
class Enumerator1
{
public @scoped Current => default;
public bool MoveNext() => false;
}
";
var comp = CreateCompilation(source);
comp.VerifyDiagnostics(
// (2,33): error CS1657: Cannot use 's1' as a ref or out value because it is a 'foreach iteration variable'
// scoped ref @scoped s2 = ref s1;
Diagnostic(ErrorCode.ERR_RefReadonlyLocalCause, "s1").WithArguments("s1", "foreach iteration variable").WithLocation(2, 33)
);
}
[Fact]
public void LocalScope_09_Foreach_02()
{
var source =
@"scoped s1 = default;
foreach (scoped ref @scoped s2 in Enumerable1.Create(ref s1)) break;
ref struct @scoped { }
class Enumerable1
{
public static Enumerable1 Create(ref @scoped p) => default;
public Enumerator1 GetEnumerator() => default;
}
class Enumerator1
{
public ref @scoped Current => throw null;
public bool MoveNext() => false;
}
";
var comp = CreateCompilation(source);
comp.VerifyDiagnostics();
}
[Fact]
public void LocalScope_10_Foreach_01()
{
var source =
@"int i = 0;
S s1 = new S(ref i);
foreach (scoped S s2 in Enumerable1.Create(s1)) break;
ref struct S
{
public S(ref int i) { }
}
class Enumerable1
{
public static Enumerable1 Create(S p) => default;
public Enumerator1 GetEnumerator() => default;
}
class Enumerator1
{
public S Current => throw null;
public bool MoveNext() => false;
}
";
var comp = CreateCompilation(source);
comp.VerifyDiagnostics();
}
[Theory]
[InlineData("class")]
[InlineData("ref struct")]
public void LocalScope_10_Foreach_02(string kind)
{
var source =
@"int i = 0;
foreach (S s1 in Enumerable1.Create(ref i)) {
scoped S s2 = s1;
break;
}
ref struct S
{
public S(ref int i) { }
}
" + kind + @" Enumerable1
{
public static Enumerable1 Create(ref int p) => default;
public Enumerator1 GetEnumerator() => default;
}
class Enumerator1
{
public S Current => throw null;
public bool MoveNext() => false;
}
";
var comp = CreateCompilation(source);
comp.VerifyDiagnostics();
}
[Fact]
public void LocalScope_11_Foreach_01()
{
var source =
@"class Program
{
static void Main()
{
S s0 = default;
scoped ref S r0 = ref s0;
foreach (scoped ref S r1 in ClassEnumerable.Create(ref s0)) {
r0 = ref r1; // 1
break;
}
foreach (scoped ref S r2 in ClassEnumerable.Create(ref s0)) {
r0 = ref r2; // 2
break;
}
foreach (ref S r3 in ClassEnumerable.Create(ref s0)) {
r0 = ref r3;
break;
}
foreach (ref S r4 in ClassEnumerable.Create(ref s0)) {
r0 = ref r4;
break;
}
foreach (scoped ref S r5 in RefStructEnumerable.Create(ref s0)) {
r0 = ref r5; // 3
break;
}
foreach (ref S r6 in RefStructEnumerable.Create(ref s0)) {
r0 = ref r6; // 4
break;
}
}
}
ref struct S { }
class ClassEnumerable
{
public static ClassEnumerable Create(ref S p) => default;
public ClassEnumerator GetEnumerator() => default;
}
ref struct RefStructEnumerable
{
public static RefStructEnumerable Create(ref S p) => default;
public ClassEnumerator GetEnumerator() => default;
}
class ClassEnumerator
{
public ref S Current => throw null;
public bool MoveNext() => false;
}
";
var comp = CreateCompilation(source);
comp.VerifyDiagnostics(
// (8,13): error CS8374: Cannot ref-assign 'r1' to 'r0' because 'r1' has a narrower escape scope than 'r0'.
// r0 = ref r1; // 1
Diagnostic(ErrorCode.ERR_RefAssignNarrower, "r0 = ref r1").WithArguments("r0", "r1").WithLocation(8, 13),
// (12,13): error CS8374: Cannot ref-assign 'r2' to 'r0' because 'r2' has a narrower escape scope than 'r0'.
// r0 = ref r2; // 2
Diagnostic(ErrorCode.ERR_RefAssignNarrower, "r0 = ref r2").WithArguments("r0", "r2").WithLocation(12, 13),
// (24,13): error CS8374: Cannot ref-assign 'r5' to 'r0' because 'r5' has a narrower escape scope than 'r0'.
// r0 = ref r5; // 3
Diagnostic(ErrorCode.ERR_RefAssignNarrower, "r0 = ref r5").WithArguments("r0", "r5").WithLocation(24, 13),
// (28,22): error CS8352: Cannot use variable 'r6' in this context because it may expose referenced variables outside of their declaration scope
// r0 = ref r6; // 4
Diagnostic(ErrorCode.ERR_EscapeVariable, "r6").WithArguments("r6").WithLocation(28, 22));
}
[Theory]
[InlineData("class")]
[InlineData("ref struct")]
public void LocalScope_11_Foreach_02(string kind)
{
var source =
@"class Program
{
static void Main()
{
S s0 = default;
foreach (scoped ref S r0 in Enumerable1.Create(ref s0))
{
scoped ref S r1 = ref s0;
r0 = ref r1;
scoped ref S r2 = ref r0;
r0 = ref r2;
ref S r3 = ref s0;
r0 = ref r3;
ref S r4 = ref r0;
r0 = ref r4;
break;
}
}
}
ref struct S { }
" + kind + @" Enumerable1
{
public static Enumerable1 Create(ref S p) => default;
public Enumerator1 GetEnumerator() => default;
}
class Enumerator1
{
public ref S Current => throw null;
public bool MoveNext() => false;
}
";
var comp = CreateCompilation(source);
comp.VerifyDiagnostics(
// (9,13): error CS1656: Cannot assign to 'r0' because it is a 'foreach iteration variable'
// r0 = ref r1;
Diagnostic(ErrorCode.ERR_AssgReadonlyLocalCause, "r0").WithArguments("r0", "foreach iteration variable").WithLocation(9, 13),
// (12,13): error CS1656: Cannot assign to 'r0' because it is a 'foreach iteration variable'
// r0 = ref r2;
Diagnostic(ErrorCode.ERR_AssgReadonlyLocalCause, "r0").WithArguments("r0", "foreach iteration variable").WithLocation(12, 13),
// (15,13): error CS1656: Cannot assign to 'r0' because it is a 'foreach iteration variable'
// r0 = ref r3;
Diagnostic(ErrorCode.ERR_AssgReadonlyLocalCause, "r0").WithArguments("r0", "foreach iteration variable").WithLocation(15, 13),
// (18,13): error CS1656: Cannot assign to 'r0' because it is a 'foreach iteration variable'
// r0 = ref r4;
Diagnostic(ErrorCode.ERR_AssgReadonlyLocalCause, "r0").WithArguments("r0", "foreach iteration variable").WithLocation(18, 13)
);
}
[Fact]
[WorkItem(64218, "https://github.com/dotnet/roslyn/issues/64218")]
public void LocalScope_12_Foreach_01()
{
var source =
@"class Program
{
static void Main()
{
int i0 = 0;
S s0 = new S(ref i0);
{
int i1 = 1;
foreach (S s1 in Enumerable1.Create(ref i1)) {
s0 = s1;
break;
}
}
foreach (scoped S s2 in Enumerable1.Create(s0)) {
s0 = s2; // 1
break;
}
foreach (S s3 in Enumerable1.Create(s0)) {
s0 = s3;
break;
}
}
}
ref struct S
{
public S(ref int i) { }
}
class Enumerable1
{
public static Enumerable1 Create(ref int p) => default;
public static Enumerable1 Create(S p) => default;
public Enumerator1 GetEnumerator() => default;
}
class Enumerator1
{
public S Current => throw null;
public bool MoveNext() => false;
}
";
var comp = CreateCompilation(source);
comp.VerifyDiagnostics(
// (15,18): error CS8352: Cannot use variable 's2' in this context because it may expose referenced variables outside of their declaration scope
// s0 = s2; // 1
Diagnostic(ErrorCode.ERR_EscapeVariable, "s2").WithArguments("s2").WithLocation(15, 18)
);
}
[Theory]
[InlineData("class")]
[InlineData("ref struct")]
public void LocalScope_12_Foreach_02(string kind)
{
var source =
@"class Program
{
static void Main()
{
int i0 = 0;
foreach (S s0 in Enumerable1.Create(ref i0))
{
int i1 = 1;
S s1 = new S(ref i1);
s0 = s1;
scoped S s2 = s0;
s0 = s2;
S s3 = s0;
s0 = s3;
break;
}
}
}
ref struct S
{
public S(ref int i) { }
}
" + kind + @" Enumerable1
{
public static Enumerable1 Create(ref int p) => default;
public Enumerator1 GetEnumerator() => default;
}
class Enumerator1
{
public S Current => throw null;
public bool MoveNext() => false;
}
";
var comp = CreateCompilation(source);
comp.VerifyDiagnostics(
// (10,13): error CS1656: Cannot assign to 's0' because it is a 'foreach iteration variable'
// s0 = s1;
Diagnostic(ErrorCode.ERR_AssgReadonlyLocalCause, "s0").WithArguments("s0", "foreach iteration variable").WithLocation(10, 13),
// (13,13): error CS1656: Cannot assign to 's0' because it is a 'foreach iteration variable'
// s0 = s2;
Diagnostic(ErrorCode.ERR_AssgReadonlyLocalCause, "s0").WithArguments("s0", "foreach iteration variable").WithLocation(13, 13),
// (16,13): error CS1656: Cannot assign to 's0' because it is a 'foreach iteration variable'
// s0 = s3;
Diagnostic(ErrorCode.ERR_AssgReadonlyLocalCause, "s0").WithArguments("s0", "foreach iteration variable").WithLocation(16, 13)
);
}
[Fact]
[WorkItem(64218, "https://github.com/dotnet/roslyn/issues/64218")]
public void LocalScope_12_Foreach_03()
{
var source =
@"class Program
{
static void Main()
{
int i0 = 0;
S s0 = new S(ref i0);
{
int i1 = 1;
foreach (S s1 in Enumerable1.Create(ref i1)) {
s0 = s1;
break;
}
}
}
}
ref struct S
{
public S(ref int i) { }
}
ref struct Enumerable1
{
public static Enumerable1 Create(ref int p) => default;
public Enumerator1 GetEnumerator() => default;
}
ref struct Enumerator1
{
public S Current => throw null;
public bool MoveNext() => false;
}
";
var comp = CreateCompilation(source);
comp.VerifyDiagnostics(
// (10,22): error CS8352: Cannot use variable 's1' in this context because it may expose referenced variables outside of their declaration scope
// s0 = s1;
Diagnostic(ErrorCode.ERR_EscapeVariable, "s1").WithArguments("s1").WithLocation(10, 22)
);
}
[Fact]
[WorkItem(64218, "https://github.com/dotnet/roslyn/issues/64218")]
public void LocalScope_12_Foreach_04()
{
var source =
@"class Program
{
static void Main()
{
int i0 = 0;
S s0 = new S(ref i0);
{
int i1 = 1;
foreach (S s1 in RefStructEnumerable.Create(ref i1)) {
s0 = s1;
break;
}
}
{
int i2 = 1;
foreach (S s2 in ClassEnumerable.Create(ref i2)) {
s0 = s2;
break;
}
}
}
}
ref struct S
{
public S(ref int i) { }
}
ref struct RefStructEnumerable
{
public static RefStructEnumerable Create(ref int p) => default;
public ClassEnumerator GetEnumerator() => default;
}
class ClassEnumerable
{
public static ClassEnumerable Create(ref int p) => default;
public ClassEnumerator GetEnumerator() => default;
}
class ClassEnumerator
{
public S Current => throw null;
public bool MoveNext() => false;
}
";
var comp = CreateCompilation(source);
comp.VerifyDiagnostics(
// (10,22): error CS8352: Cannot use variable 's1' in this context because it may expose referenced variables outside of their declaration scope
// s0 = s1;
Diagnostic(ErrorCode.ERR_EscapeVariable, "s1").WithArguments("s1").WithLocation(10, 22));
}
[Fact]
public void ScopedRefAndRefStructOnly_06_Foreach()
{
var source =
@"
struct S<T> { }
class Program
{
static void Main()
{
foreach (scoped var y1 in new Enumerable1<int>()) break;
foreach (scoped ref var y3 in new Enumerable2<int>()) break;
foreach (scoped S<int> y1 in new Enumerable1<int>()) break;
foreach (scoped ref S<int> y3 in new Enumerable2<int>()) break;
}
}
class Enumerable1<T>
{
public Enumerator1<T> GetEnumerator() => default;
}
class Enumerator1<T>
{
public S<T> Current => default;
public bool MoveNext() => false;
}
class Enumerable2<T>
{
public Enumerator2<T> GetEnumerator() => default;
}
class Enumerator2<T>
{
public ref S<T> Current => throw null;
public bool MoveNext() => false;
}
";
var comp = CreateCompilation(source);
comp.VerifyDiagnostics(
// (7,25): error CS9048: The 'scoped' modifier can be used for refs and ref struct values only.
// foreach (scoped var y1 in new Enumerable1<int>()) break;
Diagnostic(ErrorCode.ERR_ScopedRefAndRefStructOnly, "var").WithLocation(7, 25),
// (9,25): error CS9048: The 'scoped' modifier can be used for refs and ref struct values only.
// foreach (scoped S<int> y1 in new Enumerable1<int>()) break;
Diagnostic(ErrorCode.ERR_ScopedRefAndRefStructOnly, "S<int>").WithLocation(9, 25)
);
}
[Fact]
public void ScopedRefAndRefStructOnly_06_Foreach_Deconstruction()
{
var source =
@"
class Program
{
static void Main()
{
foreach ((scoped var y1, scoped S<int> y2) in new Enumerable1<int>()) break;
}
}
struct S<T>
{
public void Deconstruct(out S<T> x, out S<T> y) => throw null;
}
class Enumerable1<T>
{
public Enumerator1<T> GetEnumerator() => default;
}
class Enumerator1<T>
{
public S<T> Current => default;
public bool MoveNext() => false;
}
";
var comp = CreateCompilation(source);
comp.VerifyDiagnostics(
// (6,26): error CS9048: The 'scoped' modifier can be used for refs and ref struct values only.
// foreach ((scoped var y1, scoped S<int> y2) in new Enumerable1<int>()) break;
Diagnostic(ErrorCode.ERR_ScopedRefAndRefStructOnly, "var").WithLocation(6, 26),
// (6,41): error CS9048: The 'scoped' modifier can be used for refs and ref struct values only.
// foreach ((scoped var y1, scoped S<int> y2) in new Enumerable1<int>()) break;
Diagnostic(ErrorCode.ERR_ScopedRefAndRefStructOnly, "S<int>").WithLocation(6, 41)
);
}
private static void VerifyLocalSymbol(LocalSymbol local, string expectedDisplayString, RefKind expectedRefKind, ScopedKind expectedScope)
{
Assert.Equal(expectedRefKind, local.RefKind);
Assert.Equal(expectedScope, local.Scope);
Assert.Equal(expectedDisplayString, local.ToDisplayString(displayFormatWithScoped));
VerifyLocalSymbol(local.GetPublicSymbol(), expectedDisplayString, expectedRefKind, expectedScope);
}
private static void VerifyLocalSymbol(ILocalSymbol local, string expectedDisplayString, RefKind expectedRefKind, ScopedKind expectedScope)
{
Assert.Equal(expectedRefKind, local.RefKind);
Assert.Equal(expectedScope, local.ScopedKind);
Assert.Equal(expectedDisplayString, local.ToDisplayString(displayFormatWithScoped));
}
[ConditionalFact(typeof(WindowsDesktopOnly), Reason = ConditionalSkipReason.NoPiaNeedsDesktop)]
public void ParameterScope_EmbeddedMethod()
{
var sourceA =
@"using System.Runtime.InteropServices;
[assembly: ImportedFromTypeLib(""_.dll"")]
[assembly: Guid(""DB204C34-AE89-49C6-9174-09F72E7F7F10"")]
[ComImport()]
[Guid(""933FEEE7-2728-4F87-A802-953F3CF1B1E9"")]
public interface I
{
void M(scoped ref int i);
}
";
var comp = CreateCompilation(sourceA);
var refA = comp.EmitToImageReference(embedInteropTypes: true);
var sourceB =
@"class C : I
{
public void M(scoped ref int i) { }
}
class Program
{
static void Main()
{
}
}";
CompileAndVerify(sourceB, references: new[] { refA },
symbolValidator: module =>
{
var method = module.GlobalNamespace.GetMember<PEMethodSymbol>("I.M");
// Attribute is not included for the parameter from the embedded method.
VerifyParameterSymbol(method.Parameters[0], "ref System.Int32 i", RefKind.Ref, ScopedKind.None);
});
}
[Fact]
public void Conversions_01()
{
var source =
@"ref struct R { }
class Program
{
static R Implicit1(scoped R r) => r;
static R Implicit2(ref R r) => r;
static R Implicit4(scoped ref R r) => r;
static R Explicit1(scoped R r) => (R)r;
static R Explicit2(ref R r) => (R)r;
static R Explicit4(scoped ref R r) => (R)r;
}";
var comp = CreateCompilation(source);
comp.VerifyDiagnostics(
// (4,39): error CS8352: Cannot use variable 'scoped R r' in this context because it may expose referenced variables outside of their declaration scope
// static R Implicit1(scoped R r) => r;
Diagnostic(ErrorCode.ERR_EscapeVariable, "r").WithArguments("scoped R r").WithLocation(4, 39),
// (7,39): error CS8352: Cannot use variable 'scoped R r' in this context because it may expose referenced variables outside of their declaration scope
// static R Explicit1(scoped R r) => (R)r;
Diagnostic(ErrorCode.ERR_EscapeVariable, "(R)r").WithArguments("scoped R r").WithLocation(7, 39));
}
[Fact]
public void DelegateConversions_01()
{
var source =
@"ref struct R { }
delegate R D1(R x, R y);
delegate R D2(R x, scoped R y);
delegate ref R D3(ref R x, ref R y);
delegate ref R D5(ref R x, scoped ref R y);
class Program
{
static void Implicit()
{
D1 d1 = (R x, scoped R y) => x;
D2 d2 = (R x, R y) => x; // 1
D3 d3 = (ref R x, scoped ref R y) => ref x;
D5 d5 = (ref R x, ref R y) => ref x; // 2
}
static void Explicit()
{
var d1 = (D1)((R x, scoped R y) => x);
var d2 = (D2)((R x, R y) => x); // 3
var d3 = (D3)((ref R x, scoped ref R y) => ref x);
var d5 = (D5)((ref R x, ref R y) => ref x); // 4
}
static void New()
{
var d1 = new D1((R x, scoped R y) => x);
var d2 = new D2((R x, R y) => x); // 5
var d3 = new D3((ref R x, scoped ref R y) => ref x);
var d5 = new D5((ref R x, ref R y) => ref x); // 6
}
}";
var comp = CreateCompilation(source);
comp.VerifyDiagnostics(
// (11,17): error CS8986: The 'scoped' modifier of parameter 'y' doesn't match target 'D2'.
// D2 d2 = (R x, R y) => x; // 1
Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "(R x, R y) => x").WithArguments("y", "D2").WithLocation(11, 17),
// (13,17): error CS8986: The 'scoped' modifier of parameter 'y' doesn't match target 'D5'.
// D5 d5 = (ref R x, ref R y) => ref x; // 2
Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "(ref R x, ref R y) => ref x").WithArguments("y", "D5").WithLocation(13, 17),
// (18,18): error CS8986: The 'scoped' modifier of parameter 'y' doesn't match target 'D2'.
// var d2 = (D2)((R x, R y) => x); // 3
Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "(D2)((R x, R y) => x)").WithArguments("y", "D2").WithLocation(18, 18),
// (20,18): error CS8986: The 'scoped' modifier of parameter 'y' doesn't match target 'D5'.
// var d5 = (D5)((ref R x, ref R y) => ref x); // 4
Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "(D5)((ref R x, ref R y) => ref x)").WithArguments("y", "D5").WithLocation(20, 18),
// (25,25): error CS8986: The 'scoped' modifier of parameter 'y' doesn't match target 'D2'.
// var d2 = new D2((R x, R y) => x); // 5
Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "(R x, R y) => x").WithArguments("y", "D2").WithLocation(25, 25),
// (27,25): error CS8986: The 'scoped' modifier of parameter 'y' doesn't match target 'D5'.
// var d5 = new D5((ref R x, ref R y) => ref x); // 6
Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "(ref R x, ref R y) => ref x").WithArguments("y", "D5").WithLocation(27, 25));
}
[Fact]
public void DelegateConversions_02()
{
var source =
@"ref struct R { }
delegate R D1(R x, R y);
delegate R D2(R x, scoped R y);
delegate ref R D3(ref R x, ref R y);
delegate ref R D5(ref R x, scoped ref R y);
class Program
{
static R M1(R x, R y) => x;
static R M2(R x, scoped R y) => x;
static ref R M3(ref R x, ref R y) => ref x;
static ref R M5(ref R x, scoped ref R y) => ref x;
static void Implicit()
{
D1 d1 = M2;
D2 d2 = M1; // 1
D3 d3 = M5;
D5 d5 = M3; // 2
}
static void Explicit()
{
var d1 = (D1)M2;
var d2 = (D2)M1; // 3
var d3 = (D3)M5;
var d5 = (D5)M3; // 4
}
static void New()
{
var d1 = new D1(M2);
var d2 = new D2(M1); // 5
var d3 = new D3(M5);
var d5 = new D5(M3); // 6
}
}";
var comp = CreateCompilation(source);
comp.VerifyDiagnostics(
// (15,17): error CS8986: The 'scoped' modifier of parameter 'y' doesn't match target 'D2'.
// D2 d2 = M1; // 1
Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "M1").WithArguments("y", "D2").WithLocation(15, 17),
// (17,17): error CS8986: The 'scoped' modifier of parameter 'y' doesn't match target 'D5'.
// D5 d5 = M3; // 2
Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "M3").WithArguments("y", "D5").WithLocation(17, 17),
// (22,18): error CS8986: The 'scoped' modifier of parameter 'y' doesn't match target 'D2'.
// var d2 = (D2)M1; // 3
Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "(D2)M1").WithArguments("y", "D2").WithLocation(22, 18),
// (24,18): error CS8986: The 'scoped' modifier of parameter 'y' doesn't match target 'D5'.
// var d5 = (D5)M3; // 4
Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "(D5)M3").WithArguments("y", "D5").WithLocation(24, 18),
// (29,25): error CS8986: The 'scoped' modifier of parameter 'y' doesn't match target 'D2'.
// var d2 = new D2(M1); // 5
Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "M1").WithArguments("y", "D2").WithLocation(29, 25),
// (31,25): error CS8986: The 'scoped' modifier of parameter 'y' doesn't match target 'D5'.
// var d5 = new D5(M3); // 6
Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "M3").WithArguments("y", "D5").WithLocation(31, 25));
}
[Fact]
public void DelegateConversions_03()
{
var source =
@"delegate ref int D1(ref int x, ref int y);
delegate ref int D2(scoped ref int x, ref int y);
delegate D1 D1R();
delegate D2 D2R();
class Program
{
static void Implicit()
{
D1R d1 = () => (scoped ref int x, ref int y) => ref y;
D2R d2 = () => (ref int x, ref int y) => ref x; // 1
}
static void Explicit()
{
var d1 = (D1R)(() => (scoped ref int x, ref int y) => ref y);
var d2 = (D2R)(() => (ref int x, ref int y) => ref x); // 2
}
static void New()
{
var d1 = new D1R(() => (scoped ref int x, ref int y) => ref y);
var d2 = new D2R(() => (ref int x, ref int y) => ref x); // 3
}
}";
var comp = CreateCompilation(source);
comp.VerifyDiagnostics(
// (10,24): error CS8986: The 'scoped' modifier of parameter 'x' doesn't match target 'D2'.
// D2R d2 = () => (ref int x, ref int y) => ref x; // 1
Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "(ref int x, ref int y) => ref x").WithArguments("x", "D2").WithLocation(10, 24),
// (15,30): error CS8986: The 'scoped' modifier of parameter 'x' doesn't match target 'D2'.
// var d2 = (D2R)(() => (ref int x, ref int y) => ref x); // 2
Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "(ref int x, ref int y) => ref x").WithArguments("x", "D2").WithLocation(15, 30),
// (20,32): error CS8986: The 'scoped' modifier of parameter 'x' doesn't match target 'D2'.
// var d2 = new D2R(() => (ref int x, ref int y) => ref x); // 3
Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "(ref int x, ref int y) => ref x").WithArguments("x", "D2").WithLocation(20, 32));
}
[Fact]
public void DelegateConversions_04()
{
var source =
@"delegate ref int D1(ref int x, ref int y);
delegate ref int D2(scoped ref int x, ref int y);
delegate D1 D1R();
delegate D2 D2R();
class Program
{
static ref int M1(ref int x, ref int y) => ref x;
static ref int M2(scoped ref int x, ref int y) => ref y;
static void Implicit()
{
D1R d1 = () => M2;
D2R d2 = () => M1; // 1
}
static void Explicit()
{
var d1 = (D1R)M2;
var d2 = (D2R)M1; // 2
}
static void New()
{
var d1 = new D1R(M2);
var d2 = new D2R(M1); // 3
}
}";
var comp = CreateCompilation(source);
comp.VerifyDiagnostics(
// (12,24): error CS8986: The 'scoped' modifier of parameter 'x' doesn't match target 'D2'.
// D2R d2 = () => M1; // 1
Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "M1").WithArguments("x", "D2").WithLocation(12, 24),
// (16,18): error CS0123: No overload for 'M2' matches delegate 'D1R'
// var d1 = (D1R)M2;
Diagnostic(ErrorCode.ERR_MethDelegateMismatch, "(D1R)M2").WithArguments("M2", "D1R").WithLocation(16, 18),
// (17,18): error CS0123: No overload for 'M1' matches delegate 'D2R'
// var d2 = (D2R)M1; // 2
Diagnostic(ErrorCode.ERR_MethDelegateMismatch, "(D2R)M1").WithArguments("M1", "D2R").WithLocation(17, 18),
// (21,18): error CS0123: No overload for 'M2' matches delegate 'D1R'
// var d1 = new D1R(M2);
Diagnostic(ErrorCode.ERR_MethDelegateMismatch, "new D1R(M2)").WithArguments("M2", "D1R").WithLocation(21, 18),
// (22,18): error CS0123: No overload for 'M1' matches delegate 'D2R'
// var d2 = new D2R(M1); // 3
Diagnostic(ErrorCode.ERR_MethDelegateMismatch, "new D2R(M1)").WithArguments("M1", "D2R").WithLocation(22, 18));
}
[Fact]
public void DelegateConversions_05()
{
var source =
@"ref struct R { }
delegate R D1(R x, R y);
delegate R D2(R x, scoped R y);
delegate ref R D3(ref R x, ref R y);
delegate ref R D5(ref R x, scoped ref R y);
class Program
{
static void Implicit()
{
D1 d1 = delegate(R x, scoped R y) { return x; };
D2 d2 = delegate(R x, R y) { return x; }; // 1
D3 d3 = delegate(ref R x, scoped ref R y) { return ref x; };
D5 d5 = delegate(ref R x, ref R y) { return ref x; }; // 2
}
static void Explicit()
{
var d1 = (D1)(delegate(R x, scoped R y) { return x; });
var d2 = (D2)(delegate(R x, R y) { return x; }); // 3
var d3 = (D3)(delegate(ref R x, scoped ref R y) { return ref x; });
var d5 = (D5)(delegate(ref R x, ref R y) { return ref x; }); // 4
}
static void New()
{
var d1 = new D1(delegate(R x, scoped R y) { return x; });
var d2 = new D2(delegate(R x, R y) { return x; }); // 5
var d3 = new D3(delegate(ref R x, scoped ref R y) { return ref x; });
var d5 = new D5(delegate(ref R x, ref R y) { return ref x; }); // 6
}
}";
var comp = CreateCompilation(source);
comp.VerifyDiagnostics(
// (11,17): error CS8986: The 'scoped' modifier of parameter 'y' doesn't match target 'D2'.
// D2 d2 = delegate(R x, R y) { return x; }; // 1
Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "delegate(R x, R y) { return x; }").WithArguments("y", "D2").WithLocation(11, 17),
// (13,17): error CS8986: The 'scoped' modifier of parameter 'y' doesn't match target 'D5'.
// D5 d5 = delegate(ref R x, ref R y) { return ref x; }; // 2
Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "delegate(ref R x, ref R y) { return ref x; }").WithArguments("y", "D5").WithLocation(13, 17),
// (18,18): error CS8986: The 'scoped' modifier of parameter 'y' doesn't match target 'D2'.
// var d2 = (D2)(delegate(R x, R y) { return x; }); // 3
Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "(D2)(delegate(R x, R y) { return x; })").WithArguments("y", "D2").WithLocation(18, 18),
// (20,18): error CS8986: The 'scoped' modifier of parameter 'y' doesn't match target 'D5'.
// var d5 = (D5)(delegate(ref R x, ref R y) { return ref x; }); // 4
Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "(D5)(delegate(ref R x, ref R y) { return ref x; })").WithArguments("y", "D5").WithLocation(20, 18),
// (25,25): error CS8986: The 'scoped' modifier of parameter 'y' doesn't match target 'D2'.
// var d2 = new D2(delegate(R x, R y) { return x; }); // 5
Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "delegate(R x, R y) { return x; }").WithArguments("y", "D2").WithLocation(25, 25),
// (27,25): error CS8986: The 'scoped' modifier of parameter 'y' doesn't match target 'D5'.
// var d5 = new D5(delegate(ref R x, ref R y) { return ref x; }); // 6
Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "delegate(ref R x, ref R y) { return ref x; }").WithArguments("y", "D5").WithLocation(27, 25));
}
[Fact]
public void DelegateConversions_06()
{
var source =
@"using System.Linq.Expressions;
ref struct R { }
delegate R D1(R x, R y);
delegate R D2(R x, scoped R y);
delegate ref int D3(ref int x, ref int y);
delegate ref int D4(ref int x, scoped ref int y);
class Program
{
static void Implicit()
{
Expression<D1> e1 = (R x, scoped R y) => x;
Expression<D2> e2 = (R x, R y) => x; // 1
Expression<D3> e3 = (ref int x, scoped ref int y) => ref x;
Expression<D4> e4 = (ref int x, ref int y) => ref x; // 2
}
static void Explicit()
{
var e1 = (Expression<D1>)((R x, scoped R y) => x);
var e2 = (Expression<D2>)((R x, R y) => x); // 3
var e3 = (Expression<D3>)((ref int x, scoped ref int y) => ref x);
var e4 = (Expression<D4>)((ref int x, ref int y) => ref x); // 4
}
}";
var comp = CreateCompilation(source);
comp.VerifyDiagnostics(
// (11,32): error CS8640: Expression tree cannot contain value of ref struct or restricted type 'R'.
// Expression<D1> e1 = (R x, scoped R y) => x;
Diagnostic(ErrorCode.ERR_ExpressionTreeCantContainRefStruct, "x").WithArguments("R").WithLocation(11, 32),
// (11,44): error CS8640: Expression tree cannot contain value of ref struct or restricted type 'R'.
// Expression<D1> e1 = (R x, scoped R y) => x;
Diagnostic(ErrorCode.ERR_ExpressionTreeCantContainRefStruct, "y").WithArguments("R").WithLocation(11, 44),
// (11,50): error CS8640: Expression tree cannot contain value of ref struct or restricted type 'R'.
// Expression<D1> e1 = (R x, scoped R y) => x;
Diagnostic(ErrorCode.ERR_ExpressionTreeCantContainRefStruct, "x").WithArguments("R").WithLocation(11, 50),
// (12,29): error CS8986: The 'scoped' modifier of parameter 'y' doesn't match target 'Expression<D2>'.
// Expression<D2> e2 = (R x, R y) => x; // 1
Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "(R x, R y) => x").WithArguments("y", "System.Linq.Expressions.Expression<D2>").WithLocation(12, 29),
// (12,32): error CS8640: Expression tree cannot contain value of ref struct or restricted type 'R'.
// Expression<D2> e2 = (R x, R y) => x; // 1
Diagnostic(ErrorCode.ERR_ExpressionTreeCantContainRefStruct, "x").WithArguments("R").WithLocation(12, 32),
// (12,37): error CS8640: Expression tree cannot contain value of ref struct or restricted type 'R'.
// Expression<D2> e2 = (R x, R y) => x; // 1
Diagnostic(ErrorCode.ERR_ExpressionTreeCantContainRefStruct, "y").WithArguments("R").WithLocation(12, 37),
// (12,43): error CS8640: Expression tree cannot contain value of ref struct or restricted type 'R'.
// Expression<D2> e2 = (R x, R y) => x; // 1
Diagnostic(ErrorCode.ERR_ExpressionTreeCantContainRefStruct, "x").WithArguments("R").WithLocation(12, 43),
// (13,29): error CS8155: Lambda expressions that return by reference cannot be converted to expression trees
// Expression<D3> e3 = (ref int x, scoped ref int y) => ref x;
Diagnostic(ErrorCode.ERR_BadRefReturnExpressionTree, "(ref int x, scoped ref int y) => ref x").WithLocation(13, 29),
// (13,38): error CS1951: An expression tree lambda may not contain a ref, in or out parameter
// Expression<D3> e3 = (ref int x, scoped ref int y) => ref x;
Diagnostic(ErrorCode.ERR_ByRefParameterInExpressionTree, "x").WithLocation(13, 38),
// (13,56): error CS1951: An expression tree lambda may not contain a ref, in or out parameter
// Expression<D3> e3 = (ref int x, scoped ref int y) => ref x;
Diagnostic(ErrorCode.ERR_ByRefParameterInExpressionTree, "y").WithLocation(13, 56),
// (14,29): error CS8986: The 'scoped' modifier of parameter 'y' doesn't match target 'Expression<D4>'.
// Expression<D4> e4 = (ref int x, ref int y) => ref x; // 2
Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "(ref int x, ref int y) => ref x").WithArguments("y", "System.Linq.Expressions.Expression<D4>").WithLocation(14, 29),
// (14,29): error CS8155: Lambda expressions that return by reference cannot be converted to expression trees
// Expression<D4> e4 = (ref int x, ref int y) => ref x; // 2
Diagnostic(ErrorCode.ERR_BadRefReturnExpressionTree, "(ref int x, ref int y) => ref x").WithLocation(14, 29),
// (14,38): error CS1951: An expression tree lambda may not contain a ref, in or out parameter
// Expression<D4> e4 = (ref int x, ref int y) => ref x; // 2
Diagnostic(ErrorCode.ERR_ByRefParameterInExpressionTree, "x").WithLocation(14, 38),
// (14,49): error CS1951: An expression tree lambda may not contain a ref, in or out parameter
// Expression<D4> e4 = (ref int x, ref int y) => ref x; // 2
Diagnostic(ErrorCode.ERR_ByRefParameterInExpressionTree, "y").WithLocation(14, 49),
// (18,38): error CS8640: Expression tree cannot contain value of ref struct or restricted type 'R'.
// var e1 = (Expression<D1>)((R x, scoped R y) => x);
Diagnostic(ErrorCode.ERR_ExpressionTreeCantContainRefStruct, "x").WithArguments("R").WithLocation(18, 38),
// (18,50): error CS8640: Expression tree cannot contain value of ref struct or restricted type 'R'.
// var e1 = (Expression<D1>)((R x, scoped R y) => x);
Diagnostic(ErrorCode.ERR_ExpressionTreeCantContainRefStruct, "y").WithArguments("R").WithLocation(18, 50),
// (18,56): error CS8640: Expression tree cannot contain value of ref struct or restricted type 'R'.
// var e1 = (Expression<D1>)((R x, scoped R y) => x);
Diagnostic(ErrorCode.ERR_ExpressionTreeCantContainRefStruct, "x").WithArguments("R").WithLocation(18, 56),
// (19,18): error CS8986: The 'scoped' modifier of parameter 'y' doesn't match target 'Expression<D2>'.
// var e2 = (Expression<D2>)((R x, R y) => x); // 3
Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "(Expression<D2>)((R x, R y) => x)").WithArguments("y", "System.Linq.Expressions.Expression<D2>").WithLocation(19, 18),
// (19,38): error CS8640: Expression tree cannot contain value of ref struct or restricted type 'R'.
// var e2 = (Expression<D2>)((R x, R y) => x); // 3
Diagnostic(ErrorCode.ERR_ExpressionTreeCantContainRefStruct, "x").WithArguments("R").WithLocation(19, 38),
// (19,43): error CS8640: Expression tree cannot contain value of ref struct or restricted type 'R'.
// var e2 = (Expression<D2>)((R x, R y) => x); // 3
Diagnostic(ErrorCode.ERR_ExpressionTreeCantContainRefStruct, "y").WithArguments("R").WithLocation(19, 43),
// (19,49): error CS8640: Expression tree cannot contain value of ref struct or restricted type 'R'.
// var e2 = (Expression<D2>)((R x, R y) => x); // 3
Diagnostic(ErrorCode.ERR_ExpressionTreeCantContainRefStruct, "x").WithArguments("R").WithLocation(19, 49),
// (20,35): error CS8155: Lambda expressions that return by reference cannot be converted to expression trees
// var e3 = (Expression<D3>)((ref int x, scoped ref int y) => ref x);
Diagnostic(ErrorCode.ERR_BadRefReturnExpressionTree, "(ref int x, scoped ref int y) => ref x").WithLocation(20, 35),
// (20,44): error CS1951: An expression tree lambda may not contain a ref, in or out parameter
// var e3 = (Expression<D3>)((ref int x, scoped ref int y) => ref x);
Diagnostic(ErrorCode.ERR_ByRefParameterInExpressionTree, "x").WithLocation(20, 44),
// (20,62): error CS1951: An expression tree lambda may not contain a ref, in or out parameter
// var e3 = (Expression<D3>)((ref int x, scoped ref int y) => ref x);
Diagnostic(ErrorCode.ERR_ByRefParameterInExpressionTree, "y").WithLocation(20, 62),
// (21,18): error CS8986: The 'scoped' modifier of parameter 'y' doesn't match target 'Expression<D4>'.
// var e4 = (Expression<D4>)((ref int x, ref int y) => ref x); // 4
Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "(Expression<D4>)((ref int x, ref int y) => ref x)").WithArguments("y", "System.Linq.Expressions.Expression<D4>").WithLocation(21, 18),
// (21,35): error CS8155: Lambda expressions that return by reference cannot be converted to expression trees
// var e4 = (Expression<D4>)((ref int x, ref int y) => ref x); // 4
Diagnostic(ErrorCode.ERR_BadRefReturnExpressionTree, "(ref int x, ref int y) => ref x").WithLocation(21, 35),
// (21,44): error CS1951: An expression tree lambda may not contain a ref, in or out parameter
// var e4 = (Expression<D4>)((ref int x, ref int y) => ref x); // 4
Diagnostic(ErrorCode.ERR_ByRefParameterInExpressionTree, "x").WithLocation(21, 44),
// (21,55): error CS1951: An expression tree lambda may not contain a ref, in or out parameter
// var e4 = (Expression<D4>)((ref int x, ref int y) => ref x); // 4
Diagnostic(ErrorCode.ERR_ByRefParameterInExpressionTree, "y").WithLocation(21, 55));
}
[Fact]
public void DelegateConversions_07()
{
var source =
@"using System.Diagnostics.CodeAnalysis;
ref struct R<T> { }
delegate ref T D1<T>(scoped ref R<T> r);
delegate ref T D2<T>(ref R<T> r);
delegate ref T D3<T>(scoped in R<T> r);
delegate ref T D4<T>(in R<T> r);
delegate ref T D5<T>(out R<T> r);
delegate ref T D6<T>([UnscopedRef] out R<T> r);
class Program
{
static void Implicit()
{
D1<int> d1 = (ref R<int> r) => ref F(); // 1
D2<int> d2 = (scoped ref R<int> r) => ref F();
D3<int> d3 = (in R<int> r) => ref F(); // 2
D4<int> d4 = (scoped in R<int> r) => ref F();
D5<int> d5 = ([UnscopedRef] out R<int> r) => { r = default; return ref F(); }; // 3
D6<int> d6 = (out R<int> r) => { r = default; return ref F(); };
}
static void Explicit()
{
var d1 = (D1<int>)((ref R<int> r) => ref F()); // 4
var d2 = (D2<int>)((scoped ref R<int> r) => ref F());
var d3 = (D3<int>)((in R<int> r) => ref F()); // 5
var d4 = (D4<int>)((scoped in R<int> r) => ref F());
var d5 = (D5<int>)(([UnscopedRef] out R<int> r) => { r = default; return ref F(); }); // 6
var d6 = (D6<int>)((out R<int> r) => { r = default; return ref F(); });
}
static void New()
{
var d1 = new D1<int>((ref R<int> r) => ref F()); // 7
var d2 = new D2<int>((scoped ref R<int> r) => ref F());
var d3 = new D3<int>((in R<int> r) => ref F()); // 8
var d4 = new D4<int>((scoped in R<int> r) => ref F());
var d5 = new D5<int>(([UnscopedRef] out R<int> r) => { r = default; return ref F(); }); // 9
var d6 = new D6<int>((out R<int> r) => { r = default; return ref F(); });
}
static ref int F() => throw null;
}";
var comp = CreateCompilation(new[] { source, UnscopedRefAttributeDefinition });
comp.VerifyDiagnostics(
// (13,22): error CS8986: The 'scoped' modifier of parameter 'r' doesn't match target 'D1<int>'.
// D1<int> d1 = (ref R<int> r) => ref F(); // 1
Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "(ref R<int> r) => ref F()").WithArguments("r", "D1<int>").WithLocation(13, 22),
// (15,22): error CS8986: The 'scoped' modifier of parameter 'r' doesn't match target 'D3<int>'.
// D3<int> d3 = (in R<int> r) => ref F(); // 2
Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "(in R<int> r) => ref F()").WithArguments("r", "D3<int>").WithLocation(15, 22),
// (17,22): error CS8986: The 'scoped' modifier of parameter 'r' doesn't match target 'D5<int>'.
// D5<int> d5 = ([UnscopedRef] out R<int> r) => { r = default; return ref F(); }; // 3
Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "([UnscopedRef] out R<int> r) => { r = default; return ref F(); }").WithArguments("r", "D5<int>").WithLocation(17, 22),
// (22,18): error CS8986: The 'scoped' modifier of parameter 'r' doesn't match target 'D1<int>'.
// var d1 = (D1<int>)((ref R<int> r) => ref F()); // 4
Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "(D1<int>)((ref R<int> r) => ref F())").WithArguments("r", "D1<int>").WithLocation(22, 18),
// (24,18): error CS8986: The 'scoped' modifier of parameter 'r' doesn't match target 'D3<int>'.
// var d3 = (D3<int>)((in R<int> r) => ref F()); // 5
Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "(D3<int>)((in R<int> r) => ref F())").WithArguments("r", "D3<int>").WithLocation(24, 18),
// (26,18): error CS8986: The 'scoped' modifier of parameter 'r' doesn't match target 'D5<int>'.
// var d5 = (D5<int>)(([UnscopedRef] out R<int> r) => { r = default; return ref F(); }); // 6
Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "(D5<int>)(([UnscopedRef] out R<int> r) => { r = default; return ref F(); })").WithArguments("r", "D5<int>").WithLocation(26, 18),
// (31,30): error CS8986: The 'scoped' modifier of parameter 'r' doesn't match target 'D1<int>'.
// var d1 = new D1<int>((ref R<int> r) => ref F()); // 7
Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "(ref R<int> r) => ref F()").WithArguments("r", "D1<int>").WithLocation(31, 30),
// (33,30): error CS8986: The 'scoped' modifier of parameter 'r' doesn't match target 'D3<int>'.
// var d3 = new D3<int>((in R<int> r) => ref F()); // 8
Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "(in R<int> r) => ref F()").WithArguments("r", "D3<int>").WithLocation(33, 30),
// (35,30): error CS8986: The 'scoped' modifier of parameter 'r' doesn't match target 'D5<int>'.
// var d5 = new D5<int>(([UnscopedRef] out R<int> r) => { r = default; return ref F(); }); // 9
Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "([UnscopedRef] out R<int> r) => { r = default; return ref F(); }").WithArguments("r", "D5<int>").WithLocation(35, 30));
}
[Theory]
[InlineData("ref")]
[InlineData("in ")]
public void DelegateConversions_08(string refModifier)
{
var source =
$@"ref struct R<T> {{ }}
delegate void D0<T>(scoped {refModifier} T t);
delegate T D1<T>(scoped {refModifier} T t);
delegate ref T D2<T>(scoped {refModifier} T t);
delegate ref readonly T D3<T>(scoped {refModifier} T t);
delegate R<T> D4<T>(scoped {refModifier} T t);
class Program
{{
static ref int F() => throw null;
static void Main()
{{
D0<int> d0 = ({refModifier} int i) => {{ }};
D1<int> d1 = ({refModifier} int i) => F();
D2<int> d2 = ({refModifier} int i) => ref F(); // 1
D3<int> d3 = ({refModifier} int i) => ref F(); // 2
D4<int> d4 = ({refModifier} int i) => new R<int>(); // 3
}}
}}";
var comp = CreateCompilation(source);
comp.VerifyDiagnostics(
// (14,22): error CS8986: The 'scoped' modifier of parameter 'i' doesn't match target 'D2<int>'.
// D2<int> d2 = (ref int i) => ref F(); // 1
Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, $"({refModifier} int i) => ref F()").WithArguments("i", "D2<int>").WithLocation(14, 22),
// (15,22): error CS8986: The 'scoped' modifier of parameter 'i' doesn't match target 'D3<int>'.
// D3<int> d3 = (ref int i) => ref F(); // 2
Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, $"({refModifier} int i) => ref F()").WithArguments("i", "D3<int>").WithLocation(15, 22),
// (16,22): error CS8986: The 'scoped' modifier of parameter 'i' doesn't match target 'D4<int>'.
// D4<int> d4 = (ref int i) => new R<int>(); // 3
Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, $"({refModifier} int i) => new R<int>()").WithArguments("i", "D4<int>").WithLocation(16, 22));
}
[Theory]
[InlineData("ref")]
[InlineData("in ")]
public void DelegateConversions_09(string refModifier)
{
var source =
$@"ref struct R<T> {{ }}
delegate void D0<T>(scoped {refModifier} T t, R<T> r);
delegate void D1<T>(scoped {refModifier} T t, ref R<T> r);
delegate void D2<T>(scoped {refModifier} T t, in R<T> r);
delegate void D3<T>(scoped {refModifier} T t, out R<T> r);
class Program
{{
static ref int F() => throw null;
static void Main()
{{
D0<int> d0 = ({refModifier} int i, R<int> r) => {{ }};
D1<int> d1 = ({refModifier} int i, ref R<int> r) => {{ }}; // 1
D2<int> d2 = ({refModifier} int i, in R<int> r) => {{ }};
D3<int> d3 = ({refModifier} int i, out R<int> r) => {{ r = default; }}; // 2
}}
}}";
var comp = CreateCompilation(source);
comp.VerifyDiagnostics(
// (12,22): error CS8986: The 'scoped' modifier of parameter 'i' doesn't match target 'D1<int>'.
// D1<int> d1 = (ref int i, ref R<int> r) => { }; // 1
Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, $"({refModifier} int i, ref R<int> r) => {{ }}").WithArguments("i", "D1<int>").WithLocation(12, 22),
// (14,22): error CS8986: The 'scoped' modifier of parameter 'i' doesn't match target 'D3<int>'.
// D3<int> d3 = (ref int i, out R<int> r) => { r = default; }; // 2
Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, $"({refModifier} int i, out R<int> r) => {{ r = default; }}").WithArguments("i", "D3<int>").WithLocation(14, 22));
}
[Fact]
public void DelegateConversions_10()
{
var source =
@"using System.Diagnostics.CodeAnalysis;
ref struct R<T> { }
delegate R<T> D0<T>();
delegate R<T> D1<T>(T t);
delegate R<T> D2<T>(scoped ref T t);
delegate R<T> D3<T>(scoped in T t);
delegate R<T> D4A<T>(scoped out T t);
delegate R<T> D4B<T>(out T t);
delegate R<T> D5<T>(scoped R<T> r);
class Program
{
static void Main()
{
D0<int> d0 = () => new R<int>();
D1<int> d1 = (int i) => new R<int>();
D2<int> d2 = (ref int i) => new R<int>(); // 1
D3<int> d3 = (in int i) => new R<int>(); // 2
D4A<int> d4A = (out int i) => { i = 0; return new R<int>(); };
D4B<int> d4B = ([UnscopedRef] out int i) => { i = 0; return new R<int>(); }; // 3
D5<int> d5 = (R<int> r) => new R<int>(); // 4
}
}";
var comp = CreateCompilation(new[] { source, UnscopedRefAttributeDefinition });
comp.VerifyDiagnostics(
// (16,22): error CS8986: The 'scoped' modifier of parameter 'i' doesn't match target 'D2<int>'.
// D2<int> d2 = (ref int i) => new R<int>(); // 1
Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "(ref int i) => new R<int>()").WithArguments("i", "D2<int>").WithLocation(16, 22),
// (17,22): error CS8986: The 'scoped' modifier of parameter 'i' doesn't match target 'D3<int>'.
// D3<int> d3 = (in int i) => new R<int>(); // 2
Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "(in int i) => new R<int>()").WithArguments("i", "D3<int>").WithLocation(17, 22),
// (19,24): error CS8986: The 'scoped' modifier of parameter 'i' doesn't match target 'D4B<int>'.
// D4B<int> d4B = ([UnscopedRef] out int i) => { i = 0; return new R<int>(); }; // 3
Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "([UnscopedRef] out int i) => { i = 0; return new R<int>(); }").WithArguments("i", "D4B<int>").WithLocation(19, 24),
// (20,22): error CS8986: The 'scoped' modifier of parameter 'r' doesn't match target 'D5<int>'.
// D5<int> d5 = (R<int> r) => new R<int>(); // 4
Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "(R<int> r) => new R<int>()").WithArguments("r", "D5<int>").WithLocation(20, 22));
}
[Theory]
[InlineData("ref ")]
[InlineData("ref readonly")]
public void DelegateConversions_11(string refModifier)
{
var source =
$@"using System.Diagnostics.CodeAnalysis;
ref struct R<T> {{ }}
delegate {refModifier} T D0<T>();
delegate {refModifier} T D1<T>(T t);
delegate {refModifier} T D2<T>(scoped ref T t);
delegate {refModifier} T D3<T>(scoped in T t);
delegate {refModifier} T D4<T>(out T t);
delegate {refModifier} T D5<T>(scoped R<T> r);
class Program
{{
static {refModifier} int F() => throw null;
static void Main()
{{
D0<int> d0 = () => ref F();
D1<int> d1 = (int i) => ref F();
D2<int> d2 = (ref int i) => ref F(); // 1
D3<int> d3 = (in int i) => ref F(); // 2
D4<int> d4 = ([UnscopedRef] out int i) => {{ i = 0; return ref F(); }}; // 3
D5<int> d5 = (R<int> r) => ref F(); // 4
}}
}}";
var comp = CreateCompilation(new[] { source, UnscopedRefAttributeDefinition });
comp.VerifyDiagnostics(
// (16,22): error CS8986: The 'scoped' modifier of parameter 'i' doesn't match target 'D2<int>'.
// D2<int> d2 = (ref int i) => ref F(); // 1
Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "(ref int i) => ref F()").WithArguments("i", "D2<int>").WithLocation(16, 22),
// (17,22): error CS8986: The 'scoped' modifier of parameter 'i' doesn't match target 'D3<int>'.
// D3<int> d3 = (in int i) => ref F(); // 2
Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "(in int i) => ref F()").WithArguments("i", "D3<int>").WithLocation(17, 22),
// (18,22): error CS8986: The 'scoped' modifier of parameter 'i' doesn't match target 'D4<int>'.
// D4<int> d4 = ([UnscopedRef] out int i) => { i = 0; return ref F(); }; // 3
Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "([UnscopedRef] out int i) => { i = 0; return ref F(); }").WithArguments("i", "D4<int>").WithLocation(18, 22),
// (19,22): error CS8986: The 'scoped' modifier of parameter 'r' doesn't match target 'D5<int>'.
// D5<int> d5 = (R<int> r) => ref F(); // 4
Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "(R<int> r) => ref F()").WithArguments("r", "D5<int>").WithLocation(19, 22));
}
[Theory]
[InlineData("ref ")]
[InlineData("ref readonly")]
public void DelegateConversions_12(string refModifier)
{
var source =
$@"using System.Diagnostics.CodeAnalysis;
ref struct R<T> {{ }}
delegate {refModifier} T D0<T>();
delegate {refModifier} T D1<T>(T t);
delegate {refModifier} T D2<T>(ref T t);
delegate {refModifier} T D3<T>(in T t);
delegate {refModifier} T D4<T>(out T t);
delegate {refModifier} T D5<T>(R<T> r);
struct S1<T>
{{
private {refModifier} T F() => throw null;
public {refModifier} T F0() => ref F();
public {refModifier} T F1(T t) => ref F();
public {refModifier} T F2(ref T t) => ref F();
public {refModifier} T F3(in T t) => ref F();
public {refModifier} T F4(out T t) {{ t = default; return ref F(); }}
public {refModifier} T F5(R<T> r) => ref F();
}}
struct S2<T>
{{
private {refModifier} T F() => throw null;
[UnscopedRef] public {refModifier} T F0() => ref F();
[UnscopedRef] public {refModifier} T F1(T t) => ref F();
[UnscopedRef] public {refModifier} T F2(ref T t) => ref F();
[UnscopedRef] public {refModifier} T F3(in T t) => ref F();
[UnscopedRef] public {refModifier} T F4(out T t) {{ t = default; return ref F(); }}
[UnscopedRef] public {refModifier} T F5(R<T> r) => ref F();
}}
class Program
{{
static void F1<T>(ref S1<T> s1)
{{
D0<T> d0 = s1.F0;
D1<T> d1 = s1.F1;
D2<T> d2 = s1.F2;
D3<T> d3 = s1.F3;
D4<T> d4 = s1.F4;
D5<T> d5 = s1.F5;
}}
static void F2<T>(ref S2<T> s2)
{{
D0<T> d0 = s2.F0;
D1<T> d1 = s2.F1;
D2<T> d2 = s2.F2;
D3<T> d3 = s2.F3;
D4<T> d4 = s2.F4;
D5<T> d5 = s2.F5;
}}
}}";
var comp = CreateCompilation(new[] { source, UnscopedRefAttributeDefinition });
comp.VerifyDiagnostics();
}
[Fact]
public void DelegateConversions_Out()
{
var source =
@"ref struct R { }
delegate void D1(out int x, scoped out int y);
delegate void D2(out R x, scoped out R y);
class Program
{
static void Implicit()
{
D1 d1 = (scoped out int x, out int y) => { x = 0; y = 0; };
D2 d2 = (scoped out R x, out R y) => { x = default; y = default; };
}
static void Explicit()
{
var d1 = (D1)((scoped out int x, out int y) => { x = 0; y = 0; });
var d2 = (D2)((scoped out R x, out R y) => { x = default; y = default; });
}
static void New()
{
var d1 = new D1((scoped out int x, out int y) => { x = 0; y = 0; });
var d2 = new D2((scoped out R x, out R y) => { x = default; y = default; });
}
}";
var comp = CreateCompilation(source);
comp.VerifyDiagnostics();
}
[Fact]
public void DelegateConversions_ImplicitlyTypedParameter()
{
var source = """
delegate R D1(scoped R r);
public ref struct R
{
public ref int field;
}
class C
{
void M()
{
D1 d1 = r => r; // 1
D1 d1_2 = (scoped R r) => r; // 2
}
}
""";
var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70);
comp.VerifyDiagnostics(
// (12,17): error CS8986: The 'scoped' modifier of parameter 'r' doesn't match target 'D1'.
// D1 d1 = r => r; // 1
Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "r => r").WithArguments("r", "D1").WithLocation(12, 17),
// (13,35): error CS8352: Cannot use variable 'scoped R r' in this context because it may expose referenced variables outside of their declaration scope
// D1 d1_2 = (scoped R r) => r; // 2
Diagnostic(ErrorCode.ERR_EscapeVariable, "r").WithArguments("scoped R r").WithLocation(13, 35)
);
}
[Fact]
public void DelegateConversions_ImplicitlyTypedParameter_OverloadResolution()
{
var source = """
delegate R D1(scoped R r);
delegate R D2(R r);
public ref struct R
{
public ref int field;
}
class C
{
void M()
{
M2(r => r); // 1
M2((scoped R r) => r); // 2
M2(r => default); // 3
}
void M2(D1 d1) { }
void M2(D2 d2) { }
}
""";
var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70);
comp.VerifyDiagnostics(
// (13,9): error CS0121: The call is ambiguous between the following methods or properties: 'C.M2(D1)' and 'C.M2(D2)'
// M2(r => r); // 1
Diagnostic(ErrorCode.ERR_AmbigCall, "M2").WithArguments("C.M2(D1)", "C.M2(D2)").WithLocation(13, 9),
// (14,9): error CS0121: The call is ambiguous between the following methods or properties: 'C.M2(D1)' and 'C.M2(D2)'
// M2((scoped R r) => r); // 2
Diagnostic(ErrorCode.ERR_AmbigCall, "M2").WithArguments("C.M2(D1)", "C.M2(D2)").WithLocation(14, 9),
// (14,28): error CS8352: Cannot use variable 'scoped R' in this context because it may expose referenced variables outside of their declaration scope
// M2((scoped R r) => r); // 2
Diagnostic(ErrorCode.ERR_EscapeVariable, "r").WithArguments("scoped R r").WithLocation(14, 28),
// (15,9): error CS0121: The call is ambiguous between the following methods or properties: 'C.M2(D1)' and 'C.M2(D2)'
// M2(r => default); // 3
Diagnostic(ErrorCode.ERR_AmbigCall, "M2").WithArguments("C.M2(D1)", "C.M2(D2)").WithLocation(15, 9)
);
var tree = comp.SyntaxTrees.Single();
var model = comp.GetSemanticModel(tree);
var invocations = tree.GetRoot().DescendantNodes().OfType<InvocationExpressionSyntax>().ToArray();
Assert.Equal("M2(r => r)", invocations[0].ToString());
Assert.Null(model.GetSymbolInfo(invocations[0]).Symbol);
Assert.Equal("M2((scoped R r) => r)", invocations[1].ToString());
Assert.Null(model.GetSymbolInfo(invocations[1]).Symbol);
}
[Fact]
public void DelegateConversions_ImplicitlyTypedParameter_ParameterlessAnonymousMethod_Ref()
{
var source = """
delegate void D1(scoped R r1, scoped ref R r2);
public ref struct R
{
public ref int field;
}
class C
{
void M()
{
D1 d1 = delegate { };
}
}
""";
var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70);
comp.VerifyDiagnostics(
// (12,17): error CS8986: The 'scoped' modifier of parameter '<p0>' doesn't match target 'D1'.
// D1 d1 = delegate { };
Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "delegate { }").WithArguments("<p0>", "D1").WithLocation(12, 17),
// (12,17): error CS8986: The 'scoped' modifier of parameter '<p1>' doesn't match target 'D1'.
// D1 d1 = delegate { };
Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "delegate { }").WithArguments("<p1>", "D1").WithLocation(12, 17)
);
var tree = comp.SyntaxTrees.Single();
var model = comp.GetSemanticModel(tree);
var anonymousMethod = tree.GetRoot().DescendantNodes().OfType<AnonymousMethodExpressionSyntax>().Single();
Assert.Equal("delegate { }", anonymousMethod.ToString());
var method = model.GetSymbolInfo(anonymousMethod).Symbol;
Assert.Equal("lambda expression", method.ToTestDisplayString());
var parameters = method.GetParameters();
Assert.Equal("R <p0>", parameters[0].ToTestDisplayString());
Assert.Equal("ref R <p1>", parameters[1].ToTestDisplayString());
}
[Fact]
public void DelegateConversions_ImplicitlyTypedParameter_ParameterlessAnonymousMethod_Out()
{
var source = """
using System.Diagnostics.CodeAnalysis;
delegate void D1([UnscopedRef] out R r3);
public ref struct R
{
public ref int field;
}
class C
{
void M()
{
D1 d1 = delegate { };
}
}
""";
var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70);
comp.VerifyDiagnostics(
// (13,17): error CS1688: Cannot convert anonymous method block without a parameter list to delegate type 'D1' because it has one or more out parameters
// D1 d1 = delegate { };
Diagnostic(ErrorCode.ERR_CantConvAnonMethNoParams, "delegate { }").WithArguments("D1").WithLocation(13, 17)
);
var tree = comp.SyntaxTrees.Single();
var model = comp.GetSemanticModel(tree);
var anonymousMethod = tree.GetRoot().DescendantNodes().OfType<AnonymousMethodExpressionSyntax>().Single();
Assert.Equal("delegate { }", anonymousMethod.ToString());
var method = model.GetSymbolInfo(anonymousMethod).Symbol;
Assert.Equal("lambda expression", method.ToTestDisplayString());
Assert.Empty(method.GetParameters());
}
[Fact]
public void DelegateConversions_ImplicitlyTypedParameter_MissingParameters()
{
var source = """
delegate R D1(scoped R r);
public ref struct R
{
public ref int field;
}
class C
{
void M()
{
D1 d1 = () => new R();
}
}
""";
var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70);
comp.VerifyDiagnostics(
// (12,17): error CS1593: Delegate 'D1' does not take 0 arguments
// D1 d1 = () => new R();
Diagnostic(ErrorCode.ERR_BadDelArgCount, "() => new R()").WithArguments("D1", "0").WithLocation(12, 17)
);
}
[Fact]
public void DelegateConversions_ImplicitlyTypedParameter_ExtraParameters()
{
var source = """
delegate R D1();
public ref struct R
{
public ref int field;
}
class C
{
void M()
{
D1 d1 = r => r;
D1 d2 = (scoped R r) => r;
}
}
""";
var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70);
comp.VerifyDiagnostics(
// (12,17): error CS1593: Delegate 'D1' does not take 1 arguments
// D1 d1 = r => r;
Diagnostic(ErrorCode.ERR_BadDelArgCount, "r => r").WithArguments("D1", "1").WithLocation(12, 17),
// (13,17): error CS1593: Delegate 'D1' does not take 1 arguments
// D1 d2 = (scoped R r) => r;
Diagnostic(ErrorCode.ERR_BadDelArgCount, "(scoped R r) => r").WithArguments("D1", "1").WithLocation(13, 17)
);
}
[Fact]
public void DelegateConversions_ImplicitlyTypedParameter_NullableRewriteOfLambda()
{
var source = """
#nullable enable
delegate R<T> D<T>(scoped R<T> r, T t);
public ref struct R<T>
{
public ref int field;
}
class C
{
static R<T> F<T>(D<T> f, T t) => throw null!;
static void M<U>(U? u) where U : class
{
F((r1, t1) => F((r2, t2) => r2, t1), u).ToString();
}
}
""";
var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70);
comp.VerifyDiagnostics(
// (16,25): error CS8986: The 'scoped' modifier of parameter 'r2' doesn't match target 'D<U>'.
// F((r1, t1) => F((r2, t2) => r2, t1), u).ToString();
Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "(r2, t2) => r2").WithArguments("r2", "D<U>").WithLocation(16, 25));
var tree = comp.SyntaxTrees.Single();
var model = comp.GetSemanticModel(tree);
var lambdas = tree.GetRoot().DescendantNodes().OfType<ParenthesizedLambdaExpressionSyntax>().ToArray();
Assert.Equal("(r1, t1) => F((r2, t2) => r2, t1)", lambdas[0].ToString());
Assert.Equal("r1", lambdas[0].ParameterList.Parameters[0].Identifier.ToString());
Assert.Equal("R<U> r1", model.GetDeclaredSymbol(lambdas[0].ParameterList.Parameters[0]).ToTestDisplayString());
Assert.Equal("t1", lambdas[0].ParameterList.Parameters[1].Identifier.ToString());
Assert.Equal("U t1", model.GetDeclaredSymbol(lambdas[0].ParameterList.Parameters[1]).ToTestDisplayString());
Assert.Equal("(r2, t2) => r2", lambdas[1].ToString());
Assert.Equal("r2", lambdas[1].ParameterList.Parameters[0].Identifier.ToString());
Assert.Equal("R<U> r2", model.GetDeclaredSymbol(lambdas[1].ParameterList.Parameters[0]).ToTestDisplayString());
Assert.Equal("t2", lambdas[1].ParameterList.Parameters[1].Identifier.ToString());
Assert.Equal("U t2", model.GetDeclaredSymbol(lambdas[1].ParameterList.Parameters[1]).ToTestDisplayString());
}
[Fact]
public void DelegateConversions_ImplicitlyTypedParameter_NestedLambdaReinference_NestedNotReinferred()
{
var source = @"
using System;
delegate R D<T>(scoped T t);
ref struct R { }
class C
{
public static Action<T> Create<T>(T t, Action<T> a) => throw null!;
public static void M(object? o)
{
var a = Create(o, o1 => {
if (o1 == null) return;
D<string> d = o2 => throw null!;
});
}
}";
var comp = CreateCompilation(source, options: WithNullableEnable());
comp.VerifyDiagnostics(
// (3,17): error CS9048: The 'scoped' modifier can be used for refs and ref struct values only.
// delegate R D<T>(scoped T t);
Diagnostic(ErrorCode.ERR_ScopedRefAndRefStructOnly, "scoped T t").WithLocation(3, 17)
);
var syntaxTree = comp.SyntaxTrees[0];
var root = syntaxTree.GetRoot();
var model = comp.GetSemanticModel(syntaxTree);
var lambda = root.DescendantNodes().OfType<LambdaExpressionSyntax>().Last();
Assert.Equal("o2 => throw null!", lambda.ToString());
var lambdaSymbol = model.GetSymbolInfo(lambda).Symbol;
Assert.Equal("System.String o2", lambdaSymbol.GetParameters()[0].ToTestDisplayString());
}
[Fact, WorkItem(64984, "https://github.com/dotnet/roslyn/issues/64984")]
public void DelegateConversions_ImplicitlyTypedParameter_Conversion()
{
// The existence of conversions with incompatible `scoped` differences affects overload resolution
// Tracked by https://github.com/dotnet/roslyn/issues/64984
var source = """
ref struct R { }
delegate R D1(scoped R r);
delegate R D2(R r);
class Program
{
static void Main()
{
D1 d1 = r1 => r1; // 1
M(r2 => r2); // 2
M(r3 => default); // 3
unsafe { M(r4 => r4); } // 4
M((R r5) => r5); // 5
D1 d1_2 = (scoped R r6) => default;
M((scoped R r7) => default); // 6
D1 d1_3 = (scoped R r8) => r8; // 7
M((scoped R r9) => r9); // 8
}
static void M(D1 d1) { }
static void M(D2 d2) { }
}
""";
var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70, options: TestOptions.UnsafeDebugExe);
comp.VerifyDiagnostics(
// (10,17): error CS8986: The 'scoped' modifier of parameter 'r1' doesn't match target 'D1'.
// D1 d1 = r1 => r1; // 1
Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "r1 => r1").WithArguments("r1", "D1").WithLocation(10, 17),
// (11,9): error CS0121: The call is ambiguous between the following methods or properties: 'Program.M(D1)' and 'Program.M(D2)'
// M(r2 => r2); // 2
Diagnostic(ErrorCode.ERR_AmbigCall, "M").WithArguments("Program.M(D1)", "Program.M(D2)").WithLocation(11, 9),
// (12,9): error CS0121: The call is ambiguous between the following methods or properties: 'Program.M(D1)' and 'Program.M(D2)'
// M(r3 => default); // 3
Diagnostic(ErrorCode.ERR_AmbigCall, "M").WithArguments("Program.M(D1)", "Program.M(D2)").WithLocation(12, 9),
// (13,18): error CS0121: The call is ambiguous between the following methods or properties: 'Program.M(D1)' and 'Program.M(D2)'
// unsafe { M(r4 => r4); } // 4
Diagnostic(ErrorCode.ERR_AmbigCall, "M").WithArguments("Program.M(D1)", "Program.M(D2)").WithLocation(13, 18),
// (14,9): error CS0121: The call is ambiguous between the following methods or properties: 'Program.M(D1)' and 'Program.M(D2)'
// M((R r5) => r5); // 5
Diagnostic(ErrorCode.ERR_AmbigCall, "M").WithArguments("Program.M(D1)", "Program.M(D2)").WithLocation(14, 9),
// (17,9): error CS0121: The call is ambiguous between the following methods or properties: 'Program.M(D1)' and 'Program.M(D2)'
// M((scoped R r7) => default); // 6
Diagnostic(ErrorCode.ERR_AmbigCall, "M").WithArguments("Program.M(D1)", "Program.M(D2)").WithLocation(17, 9),
// (18,36): error CS8352: Cannot use variable 'scoped R r8' in this context because it may expose referenced variables outside of their declaration scope
// D1 d1_3 = (scoped R r8) => r8; // 7
Diagnostic(ErrorCode.ERR_EscapeVariable, "r8").WithArguments("scoped R r8").WithLocation(18, 36),
// (19,9): error CS0121: The call is ambiguous between the following methods or properties: 'Program.M(D1)' and 'Program.M(D2)'
// M((scoped R r9) => r9); // 8
Diagnostic(ErrorCode.ERR_AmbigCall, "M").WithArguments("Program.M(D1)", "Program.M(D2)").WithLocation(19, 9),
// (19,28): error CS8352: Cannot use variable 'scoped R r9' in this context because it may expose referenced variables outside of their declaration scope
// M((scoped R r9) => r9); // 8
Diagnostic(ErrorCode.ERR_EscapeVariable, "r9").WithArguments("scoped R r9").WithLocation(19, 28)
);
}
[Fact]
public void DelegateConversions_13()
{
var source = """
ref struct R { }
delegate R D1(R r);
delegate object D2(object o);
class Program
{
static void M(D1 d1) { }
static void M(D2 d2) { }
static R F(R r, ref int i) => r;
static object F(object o, ref int i) => o;
static void Main()
{
M(x =>
{
int i = 0;
return F(x, ref i);
});
}
}
""";
var comp = CreateCompilation(source);
comp.VerifyDiagnostics(
// (16,9): error CS0121: The call is ambiguous between the following methods or properties: 'Program.M(D1)' and 'Program.M(D2)'
// M(x =>
Diagnostic(ErrorCode.ERR_AmbigCall, "M").WithArguments("Program.M(D1)", "Program.M(D2)").WithLocation(16, 9));
}
[Theory]
[InlineData(LanguageVersion.CSharp10)]
[InlineData(LanguageVersion.CSharp11)]
public void DelegateConversions_14(LanguageVersion languageVersion)
{
var source = """
using System;
ref struct R { }
delegate R D1(R r);
delegate object D2(object o);
class Program
{
static void M(D1 d1) { }
static void M(D2 d2) { }
static void F(ref R x, ref Span<int> y) { }
static void F(ref object x, ref Span<int> y) { }
static void Main()
{
M(x =>
{
Span<int> y = stackalloc int[1];
F(ref x, ref y);
return x;
});
}
}
""";
var comp = CreateCompilationWithSpan(source, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion));
comp.VerifyDiagnostics(
// (18,9): error CS0121: The call is ambiguous between the following methods or properties: 'Program.M(D1)' and 'Program.M(D2)'
// M(x =>
Diagnostic(ErrorCode.ERR_AmbigCall, "M").WithArguments("Program.M(D1)", "Program.M(D2)").WithLocation(18, 9));
}
[Fact]
public void FunctionPointerConversions()
{
var source =
@"ref struct R { }
unsafe class Program
{
static R F1(R x, scoped R y) => x;
static R F2(R x, R y) => x;
static ref readonly int F3(in int x, scoped in int y) => ref x;
static ref readonly int F4(in int x, in int y) => ref x;
static void Implicit()
{
delegate*<R, scoped R, R> d1 = &F2; // 1
delegate*<R, R, R> d2 = &F1;
delegate*<in int, scoped in int, ref readonly int> d3 = &F4; // 2
delegate*<in int, in int, ref readonly int> d4 = &F3;
}
static void Explicit()
{
var d1 = (delegate*<R, scoped R, R>)&F2; // 3
var d2 = (delegate*<R, R, R>)&F1;
var d3 = (delegate*<in int, scoped in int, ref readonly int>)&F4; // 4
var d4 = (delegate*<in int, in int, ref readonly int>)&F3;
}
}";
var comp = CreateCompilation(source, options: TestOptions.UnsafeReleaseDll);
comp.VerifyDiagnostics(
// (10,22): error CS8755: 'scoped' cannot be used as a modifier on a function pointer parameter.
// delegate*<R, scoped R, R> d1 = &F2; // 1
Diagnostic(ErrorCode.ERR_BadFuncPointerParamModifier, "scoped").WithArguments("scoped").WithLocation(10, 22),
// (12,27): error CS8755: 'scoped' cannot be used as a modifier on a function pointer parameter.
// delegate*<in int, scoped in int, ref readonly int> d3 = &F4; // 2
Diagnostic(ErrorCode.ERR_BadFuncPointerParamModifier, "scoped").WithArguments("scoped").WithLocation(12, 27),
// (17,32): error CS8755: 'scoped' cannot be used as a modifier on a function pointer parameter.
// var d1 = (delegate*<R, scoped R, R>)&F2; // 3
Diagnostic(ErrorCode.ERR_BadFuncPointerParamModifier, "scoped").WithArguments("scoped").WithLocation(17, 32),
// (19,37): error CS8755: 'scoped' cannot be used as a modifier on a function pointer parameter.
// var d3 = (delegate*<in int, scoped in int, ref readonly int>)&F4; // 4
Diagnostic(ErrorCode.ERR_BadFuncPointerParamModifier, "scoped").WithArguments("scoped").WithLocation(19, 37));
}
[Fact]
public void FunctionPointerConversions_Out()
{
var source =
@"unsafe class Program
{
static void F(out int x, scoped out int y) { x = 0; y = 0; }
static void Implicit()
{
delegate*<out int, out int, void> d = &F;
}
static void Explicit()
{
var d = (delegate*<out int, out int, void>)&F;
}
}";
var comp = CreateCompilation(source, options: TestOptions.UnsafeReleaseDll);
comp.VerifyDiagnostics();
}
[Fact]
public void DuplicateMethodSignatures()
{
var source =
@"ref struct R<T> { }
class C<T>
{
static void M1(R<T> r) { }
void M2(scoped R<T> r) { }
object this[R<T> r] => null;
static void M1(scoped R<T> r) { } // 1
void M2(R<T> r) { } // 2
object this[scoped R<T> r] => null; // 3
}";
var comp = CreateCompilation(source);
comp.VerifyEmitDiagnostics(
// (7,17): error CS0111: Type 'C<T>' already defines a member called 'M1' with the same parameter types
// static void M1(scoped R<T> r) { } // 1
Diagnostic(ErrorCode.ERR_MemberAlreadyExists, "M1").WithArguments("M1", "C<T>").WithLocation(7, 17),
// (8,10): error CS0111: Type 'C<T>' already defines a member called 'M2' with the same parameter types
// void M2(R<T> r) { } // 2
Diagnostic(ErrorCode.ERR_MemberAlreadyExists, "M2").WithArguments("M2", "C<T>").WithLocation(8, 10),
// (9,12): error CS0111: Type 'C<T>' already defines a member called 'this' with the same parameter types
// object this[scoped R<T> r] => null; // 3
Diagnostic(ErrorCode.ERR_MemberAlreadyExists, "this").WithArguments("this", "C<T>").WithLocation(9, 12));
}
[Fact]
public void Overloads()
{
var source =
@"ref struct R<T> { }
class C
{
static void M1(R<int> r) { }
static void M2(scoped R<int> r) { }
static void M3(ref R<int> r) { }
static void M4(scoped ref R<int> r) { }
static void M5(scoped ref R<int> r) { }
static void M1(scoped R<int> r) { } // 2
static void M2(R<int> r) { } // 3
static void M3(scoped ref R<int> r) { } // 4
static void M4(scoped ref R<int> r) { } // 5
static void M5(ref R<int> r) { } // 6
}";
var comp = CreateCompilation(source);
comp.VerifyEmitDiagnostics(
// (9,17): error CS0111: Type 'C' already defines a member called 'M1' with the same parameter types
// static void M1(scoped R<int> r) { } // 2
Diagnostic(ErrorCode.ERR_MemberAlreadyExists, "M1").WithArguments("M1", "C").WithLocation(9, 17),
// (10,17): error CS0111: Type 'C' already defines a member called 'M2' with the same parameter types
// static void M2(R<int> r) { } // 3
Diagnostic(ErrorCode.ERR_MemberAlreadyExists, "M2").WithArguments("M2", "C").WithLocation(10, 17),
// (11,17): error CS0111: Type 'C' already defines a member called 'M3' with the same parameter types
// static void M3(scoped ref R<int> r) { } // 4
Diagnostic(ErrorCode.ERR_MemberAlreadyExists, "M3").WithArguments("M3", "C").WithLocation(11, 17),
// (12,17): error CS0111: Type 'C' already defines a member called 'M4' with the same parameter types
// static void M4(scoped ref R<int> r) { } // 5
Diagnostic(ErrorCode.ERR_MemberAlreadyExists, "M4").WithArguments("M4", "C").WithLocation(12, 17),
// (13,17): error CS0111: Type 'C' already defines a member called 'M5' with the same parameter types
// static void M5(ref R<int> r) { } // 6
Diagnostic(ErrorCode.ERR_MemberAlreadyExists, "M5").WithArguments("M5", "C").WithLocation(13, 17));
}
[Fact]
public void PartialMethods_01()
{
var sourceA =
@"ref struct R<T> { }
partial class C
{
static partial void M1(R<int> r);
static partial void M2(scoped R<int> r);
static partial void M3(ref R<int> r);
static partial void M4(scoped ref R<int> r);
static partial void M5(in R<int> r);
static partial void M6(scoped in R<int> r);
private static partial void M7(out R<int> r);
private static partial void M8(scoped out R<int> r);
}";
var sourceB1 =
@"partial class C
{
static partial void M1(R<int> r) { }
static partial void M2(scoped R<int> r) { }
static partial void M3(ref R<int> r) { }
static partial void M4(scoped ref R<int> r) { }
static partial void M5(in R<int> r) { }
static partial void M6(scoped in R<int> r) { }
private static partial void M7(out R<int> r) { r = default; }
private static partial void M8(scoped out R<int> r) { r = default; }
}";
var sourceB2 =
@"partial class C
{
static partial void M1(scoped R<int> r) { } // 1
static partial void M2(R<int> r) { } // 2
static partial void M3(scoped ref R<int> r) { } // 3
static partial void M4(ref R<int> r) { } // 4
static partial void M5(scoped in R<int> r) { } // 5
static partial void M6(in R<int> r) { } // 6
private static partial void M7(scoped out R<int> r) { r = default; }
private static partial void M8(out R<int> r) { r = default; }
}";
var comp = CreateCompilation(new[] { sourceA, sourceB1 });
comp.VerifyEmitDiagnostics();
var expectedDiagnostics = new[]
{
// (3,25): error CS8988: The 'scoped' modifier of parameter 'r' doesn't match partial method declaration.
// static partial void M1(scoped R<int> r) { } // 1
Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfPartial, "M1").WithArguments("r").WithLocation(3, 25),
// (4,25): error CS8988: The 'scoped' modifier of parameter 'r' doesn't match partial method declaration.
// static partial void M2(R<int> r) { } // 2
Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfPartial, "M2").WithArguments("r").WithLocation(4, 25),
// (5,25): error CS8988: The 'scoped' modifier of parameter 'r' doesn't match partial method declaration.
// static partial void M3(scoped ref R<int> r) { } // 3
Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfPartial, "M3").WithArguments("r").WithLocation(5, 25),
// (6,25): error CS8988: The 'scoped' modifier of parameter 'r' doesn't match partial method declaration.
// static partial void M4(ref R<int> r) { } // 4
Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfPartial, "M4").WithArguments("r").WithLocation(6, 25),
// (7,25): error CS8988: The 'scoped' modifier of parameter 'r' doesn't match partial method declaration.
// static partial void M5(scoped in R<int> r) { } // 5
Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfPartial, "M5").WithArguments("r").WithLocation(7, 25),
// (8,25): error CS8988: The 'scoped' modifier of parameter 'r' doesn't match partial method declaration.
// static partial void M6(in R<int> r) { } // 6
Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfPartial, "M6").WithArguments("r").WithLocation(8, 25)
};
comp = CreateCompilation(new[] { sourceA, sourceB2 });
comp.VerifyEmitDiagnostics(expectedDiagnostics);
comp = CreateCompilation(new[] { sourceB2, sourceA });
comp.VerifyEmitDiagnostics(expectedDiagnostics);
}
[Fact]
public void PartialMethods_02()
{
var sourceA =
@"partial class C
{
private partial void F1(ref int i);
private partial void F2(scoped ref int i);
private partial void F3(in int i);
private partial void F4(scoped ref int i);
private partial void F5(out int i);
private partial void F6(scoped out int i);
}";
var sourceB1 =
@"partial class C
{
private partial void F1(ref int i) { }
private partial void F2(scoped ref int i) { }
private partial void F3(in int i) { }
private partial void F4(scoped ref int i) { }
private partial void F5(out int i) { i = 0; }
private partial void F6(scoped out int i) { i = 0; }
}";
var sourceB2 =
@"partial class C
{
private partial void F1(scoped ref int i) { } // 1
private partial void F2(ref int i) { } // 2
private partial void F3(scoped in int i) { } // 3
private partial void F4(ref int i) { } // 4
private partial void F5(scoped out int i) { i = 0; }
private partial void F6(out int i) { i = 0; }
}";
var comp = CreateCompilation(new[] { sourceA, sourceB1 });
comp.VerifyEmitDiagnostics();
var expectedDiagnostics = new[]
{
// (3,26): error CS8988: The 'scoped' modifier of parameter 'i' doesn't match partial method declaration.
// private partial void F1(scoped ref int i) { } // 1
Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfPartial, "F1").WithArguments("i").WithLocation(3, 26),
// (4,26): error CS8988: The 'scoped' modifier of parameter 'i' doesn't match partial method declaration.
// private partial void F2(ref int i) { } // 2
Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfPartial, "F2").WithArguments("i").WithLocation(4, 26),
// (5,26): error CS8988: The 'scoped' modifier of parameter 'i' doesn't match partial method declaration.
// private partial void F3(scoped in int i) { } // 3
Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfPartial, "F3").WithArguments("i").WithLocation(5, 26),
// (6,26): error CS8988: The 'scoped' modifier of parameter 'i' doesn't match partial method declaration.
// private partial void F4(ref int i) { } // 4
Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfPartial, "F4").WithArguments("i").WithLocation(6, 26)
};
comp = CreateCompilation(new[] { sourceA, sourceB2 });
comp.VerifyEmitDiagnostics(expectedDiagnostics);
comp = CreateCompilation(new[] { sourceB2, sourceA });
comp.VerifyEmitDiagnostics(expectedDiagnostics);
}
[Fact]
public void PartialMethods_03()
{
var sourceA =
@"using System.Diagnostics.CodeAnalysis;
ref struct R { }
partial class C
{
private partial void F1(out R r);
private partial void F2([UnscopedRef] out R r);
}";
var sourceB1 =
@"partial class C
{
private partial void F1(out R r) { r = default; }
private partial void F2(out R r) { r = default; }
}";
var sourceB2 =
@"using System.Diagnostics.CodeAnalysis;
partial class C
{
private partial void F1([UnscopedRef] out R r) { r = default; }
private partial void F2(out R r) { r = default; }
}";
// Attributes are combined across partial parts so there is essentially
// no difference between the parts in these cases.
var comp = CreateCompilation(new[] { sourceA, sourceB1, UnscopedRefAttributeDefinition });
comp.VerifyEmitDiagnostics();
comp = CreateCompilation(new[] { sourceA, sourceB2, UnscopedRefAttributeDefinition });
comp.VerifyEmitDiagnostics();
comp = CreateCompilation(new[] { sourceB2, sourceA, UnscopedRefAttributeDefinition });
comp.VerifyEmitDiagnostics();
}
[CombinatorialData]
[Theory]
public void Hiding(bool useCompilationReference)
{
var sourceA =
@"public ref struct R<T> { }
public class A<T>
{
public void M1(R<T> r) { }
public void M2(scoped R<T> r) { }
public void M3(ref R<T> r) { }
public object this[R<T> r] { get { return null; } set { } }
public object this[int x, scoped R<T> y] => null;
}";
var comp = CreateCompilation(sourceA);
comp.VerifyEmitDiagnostics();
var refA = AsReference(comp, useCompilationReference);
var sourceB =
@"class B1 : A<int>
{
public new void M1(scoped R<int> r) { }
public new void M2(R<int> r) { }
public new void M3(ref R<int> r) { }
public new object this[scoped R<int> r] { get { return null; } set { } }
public new object this[int x, R<int> y] => null;
}
class B2 : A<string>
{
public void M1(scoped R<string> r) { } // 1
public void M2(R<string> r) { } // 2
public void M3(scoped ref R<string> r) { } // 3
public object this[scoped R<string> r] { get { return null; } set { } } // 4
public object this[int x, R<string> y] => null; // 5
}";
comp = CreateCompilation(sourceB, references: new[] { refA });
comp.VerifyEmitDiagnostics(
// (11,17): warning CS0108: 'B2.M1(scoped R<string>)' hides inherited member 'A<string>.M1(R<string>)'. Use the new keyword if hiding was intended.
// public void M1(scoped R<string> r) { } // 1
Diagnostic(ErrorCode.WRN_NewRequired, "M1").WithArguments("B2.M1(scoped R<string>)", "A<string>.M1(R<string>)").WithLocation(11, 17),
// (12,17): warning CS0108: 'B2.M2(R<string>)' hides inherited member 'A<string>.M2(scoped R<string>)'. Use the new keyword if hiding was intended.
// public void M2(R<string> r) { } // 2
Diagnostic(ErrorCode.WRN_NewRequired, "M2").WithArguments("B2.M2(R<string>)", "A<string>.M2(scoped R<string>)").WithLocation(12, 17),
// (13,17): warning CS0108: 'B2.M3(scoped ref R<string>)' hides inherited member 'A<string>.M3(ref R<string>)'. Use the new keyword if hiding was intended.
// public void M3(scoped ref R<string> r) { } // 3
Diagnostic(ErrorCode.WRN_NewRequired, "M3").WithArguments("B2.M3(scoped ref R<string>)", "A<string>.M3(ref R<string>)").WithLocation(13, 17),
// (14,19): warning CS0108: 'B2.this[scoped R<string>]' hides inherited member 'A<string>.this[R<string>]'. Use the new keyword if hiding was intended.
// public object this[scoped R<string> r] { get { return null; } set { } } // 4
Diagnostic(ErrorCode.WRN_NewRequired, "this").WithArguments("B2.this[scoped R<string>]", "A<string>.this[R<string>]").WithLocation(14, 19),
// (15,19): warning CS0108: 'B2.this[int, R<string>]' hides inherited member 'A<string>.this[int, scoped R<string>]'. Use the new keyword if hiding was intended.
// public object this[int x, R<string> y] => null; // 5
Diagnostic(ErrorCode.WRN_NewRequired, "this").WithArguments("B2.this[int, R<string>]", "A<string>.this[int, scoped R<string>]").WithLocation(15, 19));
}
[CombinatorialData]
[Theory]
public void Overrides_01(bool useCompilationReference)
{
var sourceA =
@"public ref struct R<T> { }
public abstract class A<T>
{
public abstract R<T> F1(R<T> r);
public abstract R<T> F2(scoped R<T> r);
public abstract R<T> F3(ref R<T> r);
public abstract R<T> F4(scoped ref R<T> r);
public abstract R<T> this[R<T> r] { get; set; }
public abstract R<T> this[int x, scoped R<T> y] { get; }
}";
var comp = CreateCompilation(sourceA);
comp.VerifyEmitDiagnostics();
var refA = AsReference(comp, useCompilationReference);
var sourceB =
@"class B1 : A<int>
{
public override R<int> F1(R<int> r) => default;
public override R<int> F2(scoped R<int> r) => default;
public override R<int> F3(ref R<int> r) => default;
public override R<int> F4(scoped ref R<int> r) => default;
public override R<int> this[R<int> r] { get { return default; } set { } }
public override R<int> this[int x, scoped R<int> y] => default;
}
class B2 : A<string>
{
public override R<string> F1(scoped R<string> r) => default;
public override R<string> F2(R<string> r) => default; // 1
public override R<string> F3(scoped ref R<string> r) => default;
public override R<string> F4(ref R<string> r) => default; // 2
public override R<string> this[scoped R<string> r] { get { return default; } set { } }
public override R<string> this[int x, R<string> y] => default; // 3
}";
comp = CreateCompilation(sourceB, references: new[] { refA });
comp.VerifyEmitDiagnostics(
// (13,31): error CS8987: The 'scoped' modifier of parameter 'r' doesn't match overridden or implemented member.
// public override R<string> F2(R<string> r) => default; // 1
Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfOverrideOrImplementation, "F2").WithArguments("r").WithLocation(13, 31),
// (15,31): error CS8987: The 'scoped' modifier of parameter 'r' doesn't match overridden or implemented member.
// public override R<string> F4(ref R<string> r) => default; // 2
Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfOverrideOrImplementation, "F4").WithArguments("r").WithLocation(15, 31),
// (17,59): error CS8987: The 'scoped' modifier of parameter 'y' doesn't match overridden or implemented member.
// public override R<string> this[int x, R<string> y] => default; // 3
Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfOverrideOrImplementation, "default").WithArguments("y").WithLocation(17, 59));
}
[CombinatorialData]
[Theory]
public void Overrides_02(bool useCompilationReference)
{
var sourceA =
@"public abstract class A<T>
{
public abstract ref T F1(out T t);
public abstract ref T F2(scoped out T t);
public abstract ref T F3(ref T t);
public abstract ref T F4(scoped ref T t);
public abstract ref T F5(in T t);
public abstract ref T F6(scoped in T t);
}";
var comp = CreateCompilation(sourceA);
comp.VerifyEmitDiagnostics();
var refA = AsReference(comp, useCompilationReference);
var sourceB =
@"class B1 : A<int>
{
public override ref int F1(out int i) => throw null;
public override ref int F2(scoped out int i) => throw null;
public override ref int F3(ref int i) => throw null;
public override ref int F4(scoped ref int i) => throw null;
public override ref int F5(in int i) => throw null;
public override ref int F6(scoped in int i) => throw null;
}
class B2 : A<string>
{
public override ref string F1(scoped out string s) => throw null;
public override ref string F2(out string s) => throw null;
public override ref string F3(scoped ref string s) => throw null;
public override ref string F4(ref string s) => throw null; // 1
public override ref string F5(scoped in string s) => throw null;
public override ref string F6(in string s) => throw null; // 2
}";
comp = CreateCompilation(sourceB, references: new[] { refA });
comp.VerifyEmitDiagnostics(
// (15,32): error CS8987: The 'scoped' modifier of parameter 's' doesn't match overridden or implemented member.
// public override ref string F4(ref string s) => throw null; // 1
Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfOverrideOrImplementation, "F4").WithArguments("s").WithLocation(15, 32),
// (17,32): error CS8987: The 'scoped' modifier of parameter 's' doesn't match overridden or implemented member.
// public override ref string F6(in string s) => throw null; // 2
Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfOverrideOrImplementation, "F6").WithArguments("s").WithLocation(17, 32));
}
[CombinatorialData]
[Theory]
public void InterfaceImplementations_01(bool useCompilationReference)
{
var sourceA =
@"public ref struct R<T> { }
public interface I<T>
{
R<T> F1(R<T> r);
R<T> F2(scoped R<T> r);
R<T> F3(ref R<T> r);
R<T> F4(scoped ref R<T> r);
R<T> this[R<T> r] { get; set; }
R<T> this[int x, scoped R<T> y] { get; }
R<T> this[object x, in R<T> y] { get; set; }
R<T> this[scoped in R<T> x, int y] { get; }
}";
var comp = CreateCompilation(sourceA);
comp.VerifyEmitDiagnostics();
var refA = AsReference(comp, useCompilationReference);
var sourceB1 =
@"class C1 : I<int>
{
public R<int> F1(R<int> r) => default;
public R<int> F2(scoped R<int> r) => default;
public R<int> F3(ref R<int> r) => default;
public R<int> F4(scoped ref R<int> r) => default;
public R<int> this[R<int> r] { get { return default; } set { } }
public R<int> this[int x, scoped R<int> y] => default;
public R<int> this[object x, in R<int> y] { get { return default; } set { } }
public R<int> this[scoped in R<int> x, int y] => default;
}
class C2 : I<string>
{
public R<string> F1(scoped R<string> r) => default;
public R<string> F2(R<string> r) => default; // 1
public R<string> F3(scoped ref R<string> r) => default;
public R<string> F4(ref R<string> r) => default; // 2
public R<string> this[scoped R<string> r] { get { return default; } set { } }
public R<string> this[int x, R<string> y] => default; // 3
public R<string> this[object x, scoped in R<string> y] { get { return default; } set { } }
public R<string> this[in R<string> x, int y] => default; // 4
}";
comp = CreateCompilation(sourceB1, references: new[] { refA });
comp.VerifyEmitDiagnostics(
// (15,22): error CS8987: The 'scoped' modifier of parameter 'r' doesn't match overridden or implemented member.
// public R<string> F2(R<string> r) => default; // 1
Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfOverrideOrImplementation, "F2").WithArguments("r").WithLocation(15, 22),
// (17,22): error CS8987: The 'scoped' modifier of parameter 'r' doesn't match overridden or implemented member.
// public R<string> F4(ref R<string> r) => default; // 2
Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfOverrideOrImplementation, "F4").WithArguments("r").WithLocation(17, 22),
// (19,50): error CS8987: The 'scoped' modifier of parameter 'y' doesn't match overridden or implemented member.
// public R<string> this[int x, R<string> y] => default; // 3
Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfOverrideOrImplementation, "default").WithArguments("y").WithLocation(19, 50),
// (21,53): error CS8987: The 'scoped' modifier of parameter 'x' doesn't match overridden or implemented member.
// public R<string> this[in R<string> x, int y] => default; // 4
Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfOverrideOrImplementation, "default").WithArguments("x").WithLocation(21, 53));
var sourceB2 =
@"class C3 : I<int>
{
R<int> I<int>.F1(R<int> r) => default;
R<int> I<int>.F2(scoped R<int> r) => default;
R<int> I<int>.F3(ref R<int> r) => default;
R<int> I<int>.F4(scoped ref R<int> r) => default;
R<int> I<int>.this[R<int> r] { get { return default; } set { } }
R<int> I<int>.this[int x, scoped R<int> y] => default;
R<int> I<int>.this[object x, in R<int> y] { get { return default; } set { } }
R<int> I<int>.this[scoped in R<int> x, int y] => default;
}
class C4 : I<string>
{
R<string> I<string>.F1(scoped R<string> r) => default;
R<string> I<string>.F2(R<string> r) => default; // 1
R<string> I<string>.F3(scoped ref R<string> r) => default;
R<string> I<string>.F4(ref R<string> r) => default; // 2
R<string> I<string>.this[scoped R<string> r] { get { return default; } set { } }
R<string> I<string>.this[int x, R<string> y] => default; // 3
R<string> I<string>.this[object x, scoped in R<string> y] { get { return default; } set { } }
R<string> I<string>.this[in R<string> x, int y] => default; // 4
}";
comp = CreateCompilation(sourceB2, references: new[] { refA });
comp.VerifyEmitDiagnostics(
// (15,25): error CS8987: The 'scoped' modifier of parameter 'r' doesn't match overridden or implemented member.
// R<string> I<string>.F2(R<string> r) => default; // 1
Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfOverrideOrImplementation, "F2").WithArguments("r").WithLocation(15, 25),
// (17,25): error CS8987: The 'scoped' modifier of parameter 'r' doesn't match overridden or implemented member.
// R<string> I<string>.F4(ref R<string> r) => default; // 2
Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfOverrideOrImplementation, "F4").WithArguments("r").WithLocation(17, 25),
// (19,53): error CS8987: The 'scoped' modifier of parameter 'y' doesn't match overridden or implemented member.
// R<string> I<string>.this[int x, R<string> y] => default; // 3
Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfOverrideOrImplementation, "default").WithArguments("y").WithLocation(19, 53),
// (21,56): error CS8987: The 'scoped' modifier of parameter 'x' doesn't match overridden or implemented member.
// R<string> I<string>.this[in R<string> x, int y] => default; // 4
Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfOverrideOrImplementation, "default").WithArguments("x").WithLocation(21, 56));
}
[CombinatorialData]
[Theory]
public void InterfaceImplementations_02(bool useCompilationReference)
{
var sourceA =
@"public interface I<T>
{
ref readonly T F1(out T t);
ref readonly T F2(scoped out T t);
ref readonly T F3(ref T t);
ref readonly T F4(scoped ref T t);
ref readonly T F5(in T t);
ref readonly T F6(scoped in T t);
}";
var comp = CreateCompilation(sourceA);
comp.VerifyEmitDiagnostics();
var refA = AsReference(comp, useCompilationReference);
var sourceB1 =
@"class C1 : I<int>
{
public ref readonly int F1(out int i) => throw null;
public ref readonly int F2(scoped out int i) => throw null;
public ref readonly int F3(ref int i) => throw null;
public ref readonly int F4(scoped ref int i) => throw null;
public ref readonly int F5(in int i) => throw null;
public ref readonly int F6(scoped in int i) => throw null;
}
class C2 : I<string>
{
public ref readonly string F1(scoped out string s) => throw null;
public ref readonly string F2(out string s) => throw null;
public ref readonly string F3(scoped ref string s) => throw null;
public ref readonly string F4(ref string s) => throw null; // 1
public ref readonly string F5(scoped in string s) => throw null;
public ref readonly string F6(in string s) => throw null; // 2
}";
comp = CreateCompilation(sourceB1, references: new[] { refA });
comp.VerifyEmitDiagnostics(
// (15,32): error CS8987: The 'scoped' modifier of parameter 's' doesn't match overridden or implemented member.
// public ref readonly string F4(ref string s) => throw null; // 1
Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfOverrideOrImplementation, "F4").WithArguments("s").WithLocation(15, 32),
// (17,32): error CS8987: The 'scoped' modifier of parameter 's' doesn't match overridden or implemented member.
// public ref readonly string F6(in string s) => throw null; // 2
Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfOverrideOrImplementation, "F6").WithArguments("s").WithLocation(17, 32));
var sourceB2 =
@"class C3 : I<int>
{
ref readonly int I<int>.F1(out int i) => throw null;
ref readonly int I<int>.F2(scoped out int i) => throw null;
ref readonly int I<int>.F3(ref int i) => throw null;
ref readonly int I<int>.F4(scoped ref int i) => throw null;
ref readonly int I<int>.F5(in int i) => throw null;
ref readonly int I<int>.F6(scoped in int i) => throw null;
}
class C4 : I<string>
{
ref readonly string I<string>.F1(scoped out string s) => throw null;
ref readonly string I<string>.F2(out string s) => throw null;
ref readonly string I<string>.F3(scoped ref string s) => throw null;
ref readonly string I<string>.F4(ref string s) => throw null; // 1
ref readonly string I<string>.F5(scoped in string s) => throw null;
ref readonly string I<string>.F6(in string s) => throw null; // 2
}";
comp = CreateCompilation(sourceB2, references: new[] { refA });
comp.VerifyEmitDiagnostics(
// (15,35): error CS8987: The 'scoped' modifier of parameter 's' doesn't match overridden or implemented member.
// ref readonly string I<string>.F4(ref string s) => throw null; // 1
Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfOverrideOrImplementation, "F4").WithArguments("s").WithLocation(15, 35),
// (17,35): error CS8987: The 'scoped' modifier of parameter 's' doesn't match overridden or implemented member.
// ref readonly string I<string>.F6(in string s) => throw null; // 2
Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfOverrideOrImplementation, "F6").WithArguments("s").WithLocation(17, 35));
}
[CombinatorialData]
[Theory]
public void OverridesAndInterfaceImplementations_Out_01(bool useCompilationReference)
{
var sourceA =
@"public abstract class A<T>
{
public abstract void F1(out T t);
}
public interface I<T>
{
void F2(out T t);
}";
var comp = CreateCompilation(sourceA);
comp.VerifyEmitDiagnostics();
var refA = AsReference(comp, useCompilationReference);
var sourceB =
@"class B1 : A<int>, I<int>
{
public override void F1(scoped out int i) { i = 0; }
public void F2(scoped out int i) { i = 0; }
}
class B2 : I<string>
{
void I<string>.F2(scoped out string s) { s = null; }
}";
comp = CreateCompilation(sourceB, references: new[] { refA });
comp.VerifyEmitDiagnostics();
}
[Fact]
public void OverridesAndInterfaceImplementations_Out_02()
{
var source =
@"abstract class A
{
public abstract void F1(out int i);
public abstract void F2(scoped out int i);
}
class B : A
{
public override void F1(scoped out int i) { i = 0; }
public override void F2(out int i) { i = 0; }
}";
var comp = CreateCompilation(source);
comp.VerifyEmitDiagnostics();
}
[Fact]
public void OverridesAndInterfaceImplementations_Out_03()
{
var source =
@"interface I
{
void F1(out int i);
void F2(scoped out int i);
}
class C1 : I
{
public void F1(scoped out int i) { i = 0; }
public void F2(out int i) { i = 0; }
}
class C2 : I
{
void I.F1(scoped out int i) { i = 0; }
void I.F2(out int i) { i = 0; }
}";
var comp = CreateCompilation(source);
comp.VerifyEmitDiagnostics();
}
[Fact]
public void OverridesAndInterfaceImplementations_Out_04()
{
var source =
@"#nullable enable
abstract class A
{
public abstract void F1<T>(out T t);
public abstract void F2<T>(out T? t);
}
class B1 : A
{
public override void F1<T>(out T t) { t = default!; }
public override void F2<T>(out T? t) where T : default { t = default; }
}
class B2 : A
{
public override void F1<T>(out T? t) where T : default { t = default; }
public override void F2<T>(out T t) { t = default!; }
}";
var comp = CreateCompilation(source);
comp.VerifyEmitDiagnostics(
// (14,26): warning CS8765: Nullability of type of parameter 't' doesn't match overridden member (possibly because of nullability attributes).
// public override void F1<T>(out T? t) where T : default { t = default; }
Diagnostic(ErrorCode.WRN_TopLevelNullabilityMismatchInParameterTypeOnOverride, "F1").WithArguments("t").WithLocation(14, 26));
// https://github.com/dotnet/roslyn/issues/62780: Test with [UnscopedRef].
}
[Fact]
public void OverridesAndInterfaceImplementations_Out_05()
{
var source =
@"#nullable enable
interface I
{
void F1<T>(out T t);
void F2<T>(out T? t);
}
class C1 : I
{
public void F1<T>(out T t) { t = default!; }
public void F2<T>(out T? t) { t = default; }
}
class C2 : I
{
public void F1<T>(out T? t) { t = default; }
public void F2<T>(out T t) { t = default!; }
}
class C3 : I
{
void I.F1<T>(out T t) { t = default!; }
void I.F2<T>(out T? t) where T : default { t = default; }
}
class C4 : I
{
void I.F1<T>(out T? t) where T : default { t = default; }
void I.F2<T>(out T t) { t = default!; }
}";
var comp = CreateCompilation(source);
comp.VerifyEmitDiagnostics(
// (14,17): warning CS8767: Nullability of reference types in type of parameter 't' of 'void C2.F1<T>(out T? t)' doesn't match implicitly implemented member 'void I.F1<T>(out T t)' (possibly because of nullability attributes).
// public void F1<T>(out T? t) { t = default; }
Diagnostic(ErrorCode.WRN_TopLevelNullabilityMismatchInParameterTypeOnImplicitImplementation, "F1").WithArguments("t", "void C2.F1<T>(out T? t)", "void I.F1<T>(out T t)").WithLocation(14, 17),
// (24,12): warning CS8769: Nullability of reference types in type of parameter 't' doesn't match implemented member 'void I.F1<T>(out T t)' (possibly because of nullability attributes).
// void I.F1<T>(out T? t) where T : default { t = default; }
Diagnostic(ErrorCode.WRN_TopLevelNullabilityMismatchInParameterTypeOnExplicitImplementation, "F1").WithArguments("t", "void I.F1<T>(out T t)").WithLocation(24, 12));
// https://github.com/dotnet/roslyn/issues/62780: Test with [UnscopedRef].
}
[Fact]
public void Overrides_Example()
{
var source =
@"ref struct R
{
public ref int F;
public R(ref int i) { F = ref i; }
}
abstract class A
{
public abstract R F1(scoped R r);
public abstract R F2(R r);
}
class B : A
{
public override R F1(R r) => r;
public override R F2(scoped R r) => default;
}
class Program
{
static R F1(A a)
{
int i = 0;
return a.F1(new R(ref i));
}
static R F2(B b)
{
int i = 0;
return b.F2(new R(ref i)); // unsafe
}
static void Main()
{
R r1 = F1(new B()); // unsafe
R r2 = F2(new B());
}
}";
var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70);
comp.VerifyEmitDiagnostics(
// (13,23): error CS8987: The 'scoped' modifier of parameter 'r' doesn't match overridden or implemented member.
// public override R F1(R r) => r;
Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfOverrideOrImplementation, "F1").WithArguments("r").WithLocation(13, 23));
}
[Fact]
public void Delegates_Example()
{
var source =
@"ref struct R
{
public ref int F;
public R(ref int i) { F = ref i; }
}
delegate R D1(scoped R x);
delegate R D2(R x);
class Program
{
static R F1(D1 d1)
{
int i = 0;
return d1(new R(ref i));
}
static R F2(D2 d2)
{
int i = 0;
return d2(new R(ref i));
}
static void Main()
{
R r1 = F1((R x) => x); // unsafe
R r2 = F2((scoped R x) => default);
}
}";
var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70);
comp.VerifyEmitDiagnostics(
// (18,16): error CS8347: Cannot use a result of 'D2.Invoke(R)' in this context because it may expose variables referenced by parameter 'x' outside of their declaration scope
// return d2(new R(ref i));
Diagnostic(ErrorCode.ERR_EscapeCall, "d2(new R(ref i))").WithArguments("D2.Invoke(R)", "x").WithLocation(18, 16),
// (18,19): error CS8347: Cannot use a result of 'R.R(ref int)' in this context because it may expose variables referenced by parameter 'i' outside of their declaration scope
// return d2(new R(ref i));
Diagnostic(ErrorCode.ERR_EscapeCall, "new R(ref i)").WithArguments("R.R(ref int)", "i").WithLocation(18, 19),
// (18,29): error CS8168: Cannot return local 'i' by reference because it is not a ref local
// return d2(new R(ref i));
Diagnostic(ErrorCode.ERR_RefReturnLocal, "i").WithArguments("i").WithLocation(18, 29),
// (22,19): error CS8989: The 'scoped' modifier of parameter 'x' doesn't match target 'D1'.
// R r1 = F1((R x) => x); // unsafe
Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "(R x) => x").WithArguments("x", "D1").WithLocation(22, 19));
}
[Fact]
public void BestCommonType_01()
{
var source =
@"ref struct R { }
class Program
{
static R F1(bool b, R x, scoped R y) => b ? x : y;
static R F2(bool b, R x, scoped R y) => b ? y : x;
}";
var comp = CreateCompilation(source);
comp.VerifyDiagnostics(
// (4,53): error CS8352: Cannot use variable 'scoped R y' in this context because it may expose referenced variables outside of their declaration scope
// static R F1(bool b, R x, scoped R y) => b ? x : y;
Diagnostic(ErrorCode.ERR_EscapeVariable, "y").WithArguments("scoped R y").WithLocation(4, 53),
// (5,49): error CS8352: Cannot use variable 'scoped R y' in this context because it may expose referenced variables outside of their declaration scope
// static R F2(bool b, R x, scoped R y) => b ? y : x;
Diagnostic(ErrorCode.ERR_EscapeVariable, "y").WithArguments("scoped R y").WithLocation(5, 49));
}
[Fact]
public void BestCommonType_01_UnsafeContext()
{
var source =
@"ref struct R { }
unsafe class Program
{
static R F1(bool b, R x, scoped R y) => b ? x : y;
static R F2(bool b, R x, scoped R y) => b ? y : x;
}";
var comp = CreateCompilation(source, options: TestOptions.UnsafeDebugDll);
comp.VerifyDiagnostics(
// (4,53): warning CS9080: Use of variable 'scoped R y' in this context may expose referenced variables outside of their declaration scope
// static R F1(bool b, R x, scoped R y) => b ? x : y;
Diagnostic(ErrorCode.WRN_EscapeVariable, "y").WithArguments("scoped R y").WithLocation(4, 53),
// (5,49): warning CS9080: Use of variable 'scoped R y' in this context may expose referenced variables outside of their declaration scope
// static R F2(bool b, R x, scoped R y) => b ? y : x;
Diagnostic(ErrorCode.WRN_EscapeVariable, "y").WithArguments("scoped R y").WithLocation(5, 49));
}
[Fact]
public void BestCommonType_03()
{
var source =
@"class Program
{
static ref int F1(bool b, scoped ref int x, ref int y) => ref b ? ref x : ref y;
static ref int F2(bool b, scoped ref int x, ref int y) => ref b ? ref y : ref x;
}";
var comp = CreateCompilation(source);
comp.VerifyDiagnostics(
// (3,75): error CS9075: Cannot return a parameter by reference 'x' because it is scoped to the current method
// static ref int F1(bool b, scoped ref int x, ref int y) => ref b ? ref x : ref y;
Diagnostic(ErrorCode.ERR_RefReturnScopedParameter, "x").WithArguments("x").WithLocation(3, 75),
// (4,83): error CS9075: Cannot return a parameter by reference 'x' because it is scoped to the current method
// static ref int F2(bool b, scoped ref int x, ref int y) => ref b ? ref y : ref x;
Diagnostic(ErrorCode.ERR_RefReturnScopedParameter, "x").WithArguments("x").WithLocation(4, 83));
}
[Fact]
public void BestCommonType_04()
{
var source =
@"ref struct R { }
class Program
{
static void Main()
{
var f1 = new[] { (R r) => { }, (scoped R r) => { } }[0]; // 1
var f2 = new[] { (scoped R r) => { }, (scoped R r) => { } }[0];
var f3 = new[] { (ref R r) => { }, (scoped ref R r) => { } }[0]; // 2
var f4 = new[] { (scoped ref R r) => { }, (scoped ref R r) => { } }[0];
}
}";
var comp = CreateCompilation(source);
comp.VerifyDiagnostics(
// (6,18): error CS0826: No best type found for implicitly-typed array
// var f1 = new[] { (R r) => { }, (scoped R r) => { } }[0]; // 1
Diagnostic(ErrorCode.ERR_ImplicitlyTypedArrayNoBestType, "new[] { (R r) => { }, (scoped R r) => { } }").WithLocation(6, 18),
// (8,18): error CS0826: No best type found for implicitly-typed array
// var f3 = new[] { (ref R r) => { }, (scoped ref R r) => { } }[0]; // 2
Diagnostic(ErrorCode.ERR_ImplicitlyTypedArrayNoBestType, "new[] { (ref R r) => { }, (scoped ref R r) => { } }").WithLocation(8, 18));
}
[Fact]
public void InferredDelegateTypes_01()
{
var source =
@"ref struct R { }
class Program
{
static void F1(R x1, scoped R y1)
{
var f = (R x, scoped R y) => x;
R z;
z = f(x1, y1);
z = f(y1, x1); // 1
}
static void F3(ref int x3, scoped ref int y3)
{
var f = (ref int x, scoped ref int y) => ref x;
int z;
z = f(ref x3, ref y3);
z = f(ref y3, ref x3);
}
}";
var comp = CreateCompilation(source);
// https://github.com/dotnet/roslyn/issues/62768: Improve error message for `scoped ref` parameter returned by reference.
comp.VerifyDiagnostics(
// (9,13): error CS8347: Cannot use a result of '<anonymous delegate>.Invoke(R, scoped R)' in this context because it may expose variables referenced by parameter 'arg1' outside of their declaration scope
// z = f(y1, x1); // 1
Diagnostic(ErrorCode.ERR_EscapeCall, "f(y1, x1)").WithArguments("<anonymous delegate>.Invoke(R, scoped R)", "arg1").WithLocation(9, 13),
// (9,15): error CS8352: Cannot use variable 'scoped R y1' in this context because it may expose referenced variables outside of their declaration scope
// z = f(y1, x1); // 1
Diagnostic(ErrorCode.ERR_EscapeVariable, "y1").WithArguments("scoped R y1").WithLocation(9, 15));
var tree = comp.SyntaxTrees[0];
var model = comp.GetSemanticModel(tree);
var decls = tree.GetRoot().DescendantNodes().OfType<VariableDeclaratorSyntax>().Where(v => v.Identifier.Text == "f").ToArray();
var delegateInvokeMethods = decls.Select(d => ((ILocalSymbol)model.GetDeclaredSymbol(d)).Type.GetSymbol<NamedTypeSymbol>().DelegateInvokeMethod).ToArray();
VerifyParameterSymbol(delegateInvokeMethods[0].Parameters[0], "R arg1", RefKind.None, ScopedKind.None);
VerifyParameterSymbol(delegateInvokeMethods[0].Parameters[1], "scoped R arg2", RefKind.None, ScopedKind.ScopedValue);
VerifyParameterSymbol(delegateInvokeMethods[1].Parameters[1], "scoped ref System.Int32 arg2", RefKind.Ref, ScopedKind.ScopedRef);
}
[Fact]
public void InferredDelegateTypes_02()
{
var source =
@"ref struct R { }
static class E1
{
public static void F1(this object o, R r) { }
public static void F2(this object o, ref R r) { }
}
static class E2
{
public static void F1(this object o, scoped R r) { }
public static void F2(this object o, scoped ref R r) { }
}
class Program
{
static void Main()
{
object o = new object();
var d1 = o.F1;
var d2 = o.F2;
}
}";
var comp = CreateCompilation(source);
comp.VerifyDiagnostics(
// (17,18): error CS0121: The call is ambiguous between the following methods or properties: 'E1.F1(object, R)' and 'E2.F1(object, scoped R)'
// var d1 = o.F1;
Diagnostic(ErrorCode.ERR_AmbigCall, "o.F1").WithArguments("E1.F1(object, R)", "E2.F1(object, scoped R)").WithLocation(17, 18),
// (18,18): error CS0121: The call is ambiguous between the following methods or properties: 'E1.F2(object, ref R)' and 'E2.F2(object, scoped ref R)'
// var d2 = o.F2;
Diagnostic(ErrorCode.ERR_AmbigCall, "o.F2").WithArguments("E1.F2(object, ref R)", "E2.F2(object, scoped ref R)").WithLocation(18, 18));
}
[Fact]
public void ScopedRefAndRefStructOnly_01()
{
var source =
@"struct S { }
class Program
{
static void F1(scoped S s) { }
static void F3(scoped ref S s) { }
static void F5(scoped ref int i) { }
static void F6(scoped in int i) { }
static void F7(scoped out int i) { i = 0; }
}";
var comp = CreateCompilation(source);
comp.VerifyDiagnostics(
// (4,20): error CS9048: The 'scoped' modifier can be used for refs and ref struct values only.
// static void F1(scoped S s) { }
Diagnostic(ErrorCode.ERR_ScopedRefAndRefStructOnly, "scoped S s").WithLocation(4, 20));
}
[Fact]
public void ScopedRefAndRefStructOnly_02()
{
var source =
@"struct S { }
interface I
{
void F1<T>(scoped T t);
void F2<T>(scoped T t) where T : class;
void F3<T>(scoped T t) where T : struct;
void F4<T>(scoped T t) where T : unmanaged;
}";
var comp = CreateCompilation(source);
comp.VerifyDiagnostics(
// (4,16): error CS9048: The 'scoped' modifier can be used for refs and ref struct values only.
// void F1<T>(scoped T t);
Diagnostic(ErrorCode.ERR_ScopedRefAndRefStructOnly, "scoped T t").WithLocation(4, 16),
// (5,16): error CS9048: The 'scoped' modifier can be used for refs and ref struct values only.
// void F2<T>(scoped T t) where T : class;
Diagnostic(ErrorCode.ERR_ScopedRefAndRefStructOnly, "scoped T t").WithLocation(5, 16),
// (6,16): error CS9048: The 'scoped' modifier can be used for refs and ref struct values only.
// void F3<T>(scoped T t) where T : struct;
Diagnostic(ErrorCode.ERR_ScopedRefAndRefStructOnly, "scoped T t").WithLocation(6, 16),
// (7,16): error CS9048: The 'scoped' modifier can be used for refs and ref struct values only.
// void F4<T>(scoped T t) where T : unmanaged;
Diagnostic(ErrorCode.ERR_ScopedRefAndRefStructOnly, "scoped T t").WithLocation(7, 16));
}
[Fact]
public void ScopedRefAndRefStructOnly_03()
{
var source =
@"enum E { }
class Program
{
static void Main()
{
var f = (scoped ref E x, scoped E y) => { };
#pragma warning disable 8321
static void L(scoped ref E x, scoped E y) { }
}
}";
var comp = CreateCompilation(source);
comp.VerifyDiagnostics(
// (6,34): error CS9048: The 'scoped' modifier can be used for refs and ref struct values only.
// var f = (scoped ref E x, scoped E y) => { };
Diagnostic(ErrorCode.ERR_ScopedRefAndRefStructOnly, "scoped E y").WithLocation(6, 34),
// (8,39): error CS9048: The 'scoped' modifier can be used for refs and ref struct values only.
// static void L(scoped ref E x, scoped E y) { }
Diagnostic(ErrorCode.ERR_ScopedRefAndRefStructOnly, "scoped E y").WithLocation(8, 39));
}
[Fact]
public void ScopedRefAndRefStructOnly_04()
{
var source =
@"delegate void D(scoped C c);
class C
{
static unsafe void Main()
{
delegate*<scoped C, int> d = default;
}
}";
var comp = CreateCompilation(source, options: TestOptions.UnsafeReleaseExe);
comp.VerifyDiagnostics(
// (1,17): error CS9048: The 'scoped' modifier can be used for refs and ref struct values only.
// delegate void D(scoped C c);
Diagnostic(ErrorCode.ERR_ScopedRefAndRefStructOnly, "scoped C c").WithLocation(1, 17),
// (6,19): error CS8755: 'scoped' cannot be used as a modifier on a function pointer parameter.
// delegate*<scoped C, int> d = default;
Diagnostic(ErrorCode.ERR_BadFuncPointerParamModifier, "scoped").WithArguments("scoped").WithLocation(6, 19));
}
[Theory]
[InlineData("ref ")]
[InlineData("ref readonly")]
public void ScopedRefAndRefStructOnly_05(string refModifier)
{
var source =
$@"struct S {{ }}
class Program
{{
static void F(S s)
{{
scoped {refModifier} S s2 = ref s;
}}
}}";
var comp = CreateCompilation(source);
comp.VerifyDiagnostics();
}
[Theory]
[InlineData("ref ")]
[InlineData("ref readonly")]
public void ScopedRefAndRefStructOnly_05_RefScoped(string refModifier)
{
var source =
$@"struct S {{ }}
class Program
{{
static void F(S s)
{{
{refModifier} scoped S s1 = ref s;
scoped {refModifier} scoped S s3 = ref s;
}}
}}";
var comp = CreateCompilation(source);
comp.VerifyDiagnostics(
// (6,22): error CS0246: The type or namespace name 'scoped' could not be found (are you missing a using directive or an assembly reference?)
// ref scoped S s1 = ref s;
Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "scoped").WithArguments("scoped").WithLocation(6, 22),
// (6,29): error CS8174: A declaration of a by-reference variable must have an initializer
// ref scoped S s1 = ref s;
Diagnostic(ErrorCode.ERR_ByReferenceVariableMustBeInitialized, "S").WithLocation(6, 29),
// (6,29): warning CS0168: The variable 'S' is declared but never used
// ref scoped S s1 = ref s;
Diagnostic(ErrorCode.WRN_UnreferencedVar, "S").WithArguments("S").WithLocation(6, 29),
// (6,31): error CS1002: ; expected
// ref scoped S s1 = ref s;
Diagnostic(ErrorCode.ERR_SemicolonExpected, "s1").WithLocation(6, 31),
// (6,31): error CS0103: The name 's1' does not exist in the current context
// ref scoped S s1 = ref s;
Diagnostic(ErrorCode.ERR_NameNotInContext, "s1").WithArguments("s1").WithLocation(6, 31),
// (7,29): error CS0246: The type or namespace name 'scoped' could not be found (are you missing a using directive or an assembly reference?)
// scoped ref scoped S s3 = ref s;
Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "scoped").WithArguments("scoped").WithLocation(7, 29),
// (7,36): error CS0128: A local variable or function named 'S' is already defined in this scope
// scoped ref scoped S s3 = ref s;
Diagnostic(ErrorCode.ERR_LocalDuplicate, "S").WithArguments("S").WithLocation(7, 36),
// (7,36): error CS8174: A declaration of a by-reference variable must have an initializer
// scoped ref scoped S s3 = ref s;
Diagnostic(ErrorCode.ERR_ByReferenceVariableMustBeInitialized, "S").WithLocation(7, 36),
// (7,36): warning CS0168: The variable 'S' is declared but never used
// scoped ref scoped S s3 = ref s;
Diagnostic(ErrorCode.WRN_UnreferencedVar, "S").WithArguments("S").WithLocation(7, 36),
// (7,38): error CS1002: ; expected
// scoped ref scoped S s3 = ref s;
Diagnostic(ErrorCode.ERR_SemicolonExpected, "s3").WithLocation(7, 38),
// (7,38): error CS0103: The name 's3' does not exist in the current context
// scoped ref scoped S s3 = ref s;
Diagnostic(ErrorCode.ERR_NameNotInContext, "s3").WithArguments("s3").WithLocation(7, 38)
);
}
[Fact]
public void ScopedRefAndRefStructOnly_06()
{
var source =
@"ref struct R<T> { }
struct S<T> { }
class Program
{
static void Main()
{
scoped var x1 = new R<int>();
scoped ref var x3 = ref x1; // 1
scoped var y1 = new S<int>(); // 2
scoped ref var y3 = ref y1;
scoped S<int> y4 = new S<int>(), y5 = new S<int>(); // 3
y4 = y5;
y5 = y4;
}
}";
var comp = CreateCompilation(source);
comp.VerifyDiagnostics(
// (8,33): error CS8352: Cannot use variable 'x1' in this context because it may expose referenced variables outside of their declaration scope
// scoped ref var x3 = ref x1; // 1
Diagnostic(ErrorCode.ERR_EscapeVariable, "x1").WithArguments("x1").WithLocation(8, 33),
// (9,16): error CS9048: The 'scoped' modifier can be used for refs and ref struct values only.
// scoped var y1 = new S<int>(); // 2
Diagnostic(ErrorCode.ERR_ScopedRefAndRefStructOnly, "var").WithLocation(9, 16),
// (11,16): error CS9048: The 'scoped' modifier can be used for refs and ref struct values only.
// scoped S<int> y4 = new S<int>(), y5 = new S<int>(); // 3
Diagnostic(ErrorCode.ERR_ScopedRefAndRefStructOnly, "S<int>").WithLocation(11, 16),
// (11,16): error CS9048: The 'scoped' modifier can be used for refs and ref struct values only.
// scoped S<int> y4 = new S<int>(), y5 = new S<int>(); // 3
Diagnostic(ErrorCode.ERR_ScopedRefAndRefStructOnly, "S<int>").WithLocation(11, 16)
);
}
[Fact]
public void ScopedRefAndRefStructOnly_07()
{
var source =
@"ref struct R<T> { }
class Program
{
static void F1(scoped Unknown x, scoped R<Unknown> y)
{
var f = (scoped ref Unknown u) => { };
scoped R<Unknown> z = y;
scoped var v = F2();
}
}";
var comp = CreateCompilation(source);
comp.VerifyDiagnostics(
// (4,20): error CS9048: The 'scoped' modifier can be used for refs and ref struct values only.
// static void F1(scoped Unknown x, scoped R<Unknown> y)
Diagnostic(ErrorCode.ERR_ScopedRefAndRefStructOnly, "scoped Unknown x").WithLocation(4, 20),
// (4,27): error CS0246: The type or namespace name 'Unknown' could not be found (are you missing a using directive or an assembly reference?)
// static void F1(scoped Unknown x, scoped R<Unknown> y)
Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "Unknown").WithArguments("Unknown").WithLocation(4, 27),
// (4,47): error CS0246: The type or namespace name 'Unknown' could not be found (are you missing a using directive or an assembly reference?)
// static void F1(scoped Unknown x, scoped R<Unknown> y)
Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "Unknown").WithArguments("Unknown").WithLocation(4, 47),
// (6,29): error CS0246: The type or namespace name 'Unknown' could not be found (are you missing a using directive or an assembly reference?)
// var f = (scoped ref Unknown u) => { };
Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "Unknown").WithArguments("Unknown").WithLocation(6, 29),
// (7,18): error CS0246: The type or namespace name 'Unknown' could not be found (are you missing a using directive or an assembly reference?)
// scoped R<Unknown> z = y;
Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "Unknown").WithArguments("Unknown").WithLocation(7, 18),
// (8,24): error CS0103: The name 'F2' does not exist in the current context
// scoped var v = F2();
Diagnostic(ErrorCode.ERR_NameNotInContext, "F2").WithArguments("F2").WithLocation(8, 24));
}
[Fact]
public void Local_SequencePoints()
{
var source =
@"using System;
ref struct R<T>
{
public ref T F;
public R(ref T t) { F = ref t; }
}
class Program
{
static void Main()
{
int x = 1;
scoped R<int> y = new R<int>(ref x);
ref R<int> z = ref y;
z.F = 2;
Console.WriteLine(x);
}
}";
var comp = CreateCompilation(source, options: TestOptions.DebugExe, targetFramework: TargetFramework.Net70);
var verifier = CompileAndVerify(comp, verify: Verification.Skipped);
verifier.VerifyIL("Program.Main",
source: source,
sequencePoints: "Program.Main",
expectedIL:
@"{
// Code size 30 (0x1e)
.maxstack 2
.locals init (int V_0, //x
R<int> V_1, //y
R<int>& V_2) //z
// sequence point: {
IL_0000: nop
// sequence point: int x = 1;
IL_0001: ldc.i4.1
IL_0002: stloc.0
// sequence point: scoped R<int> y = new R<int>(ref x);
IL_0003: ldloca.s V_0
IL_0005: newobj ""R<int>..ctor(ref int)""
IL_000a: stloc.1
// sequence point: ref R<int> z = ref y;
IL_000b: ldloca.s V_1
IL_000d: stloc.2
// sequence point: z.F = 2;
IL_000e: ldloc.2
IL_000f: ldfld ""ref int R<int>.F""
IL_0014: ldc.i4.2
IL_0015: stind.i4
// sequence point: Console.WriteLine(x);
IL_0016: ldloc.0
IL_0017: call ""void System.Console.WriteLine(int)""
IL_001c: nop
// sequence point: }
IL_001d: ret
}");
}
[Fact]
public void SafeToEscape_01()
{
var source =
@"ref struct R<T> { }
class Program
{
static R<int> F0(R<int> r0) => r0;
static R<int> F1(scoped R<int> r1) => r1; // 1
static R<int> F2(ref R<int> r2) => r2;
static R<int> F3(scoped ref R<int> r3) => r3;
}";
var comp = CreateCompilation(source);
comp.VerifyDiagnostics(
// (5,43): error CS8352: Cannot use variable 'scoped R<int> r1' in this context because it may expose referenced variables outside of their declaration scope
// static R<int> F1(scoped R<int> r1) => r1; // 1
Diagnostic(ErrorCode.ERR_EscapeVariable, "r1").WithArguments("scoped R<int> r1").WithLocation(5, 43));
}
[Fact]
public void RefSafeToEscape_01()
{
var source =
@"ref struct R<T> { }
class Program
{
static ref R<int> F0(R<int> r0) => ref r0; // 1
static ref R<int> F1(scoped R<int> r1) => ref r1; // 2
static ref R<int> F2(ref R<int> r2) => ref r2;
static ref R<int> F3(scoped ref R<int> r3) => ref r3; // 3
}";
var comp = CreateCompilation(source);
comp.VerifyDiagnostics(
// (4,44): error CS8166: Cannot return a parameter by reference 'r0' because it is not a ref parameter
// static ref R<int> F0(R<int> r0) => ref r0; // 1
Diagnostic(ErrorCode.ERR_RefReturnParameter, "r0").WithArguments("r0").WithLocation(4, 44),
// (5,51): error CS8166: Cannot return a parameter by reference 'r1' because it is not a ref parameter
// static ref R<int> F1(scoped R<int> r1) => ref r1; // 2
Diagnostic(ErrorCode.ERR_RefReturnParameter, "r1").WithArguments("r1").WithLocation(5, 51),
// (7,55): error CS9075: Cannot return a parameter by reference 'r3' because it is scoped to the current method
// static ref R<int> F3(scoped ref R<int> r3) => ref r3; // 3
Diagnostic(ErrorCode.ERR_RefReturnScopedParameter, "r3").WithArguments("r3").WithLocation(7, 55));
}
[Fact]
public void SafeToEscape_02()
{
var source =
@"ref struct R<T> { }
class Program
{
static R<int> F0(R<int> r0)
{
R<int> l0 = r0;
return l0;
}
static R<int> F1(scoped R<int> r1)
{
R<int> l1 = r1;
return l1; // 1
}
static R<int> F2(ref R<int> r2)
{
R<int> l2 = r2;
return l2;
}
static R<int> F3(scoped ref R<int> r3)
{
R<int> l3 = r3;
return l3;
}
}";
var comp = CreateCompilation(source);
comp.VerifyDiagnostics(
// (12,16): error CS8352: Cannot use variable 'l1' in this context because it may expose referenced variables outside of their declaration scope
// return l1; // 1
Diagnostic(ErrorCode.ERR_EscapeVariable, "l1").WithArguments("l1").WithLocation(12, 16));
}
[Fact]
public void RefSafeToEscape_02()
{
var source =
@"ref struct R<T> { }
class Program
{
static ref R<int> F0(R<int> r0)
{
R<int> l0 = r0;
return ref l0; // 1
}
static ref R<int> F1(scoped R<int> r1)
{
R<int> l1 = r1;
return ref l1; // 2
}
static ref R<int> F2(ref R<int> r2)
{
R<int> l2 = r2;
return ref l2; // 3
}
static ref R<int> F3(scoped ref R<int> r3)
{
R<int> l3 = r3;
return ref l3; // 4
}
}";
var comp = CreateCompilation(source);
comp.VerifyDiagnostics(
// (7,20): error CS8168: Cannot return local 'l0' by reference because it is not a ref local
// return ref l0; // 1
Diagnostic(ErrorCode.ERR_RefReturnLocal, "l0").WithArguments("l0").WithLocation(7, 20),
// (12,20): error CS8168: Cannot return local 'l1' by reference because it is not a ref local
// return ref l1; // 2
Diagnostic(ErrorCode.ERR_RefReturnLocal, "l1").WithArguments("l1").WithLocation(12, 20),
// (17,20): error CS8168: Cannot return local 'l2' by reference because it is not a ref local
// return ref l2; // 3
Diagnostic(ErrorCode.ERR_RefReturnLocal, "l2").WithArguments("l2").WithLocation(17, 20),
// (22,20): error CS8168: Cannot return local 'l3' by reference because it is not a ref local
// return ref l3; // 4
Diagnostic(ErrorCode.ERR_RefReturnLocal, "l3").WithArguments("l3").WithLocation(22, 20));
}
[Fact]
public void SafeToEscape_03()
{
var source =
@"ref struct R<T> { }
class Program
{
static R<int> F0(R<int> r0)
{
scoped R<int> l0 = r0;
return l0; // 1
}
static R<int> F1(scoped R<int> r1)
{
scoped R<int> l1 = r1;
return l1; // 2
}
static R<int> F2(ref R<int> r2)
{
scoped R<int> l2 = r2;
return l2; // 3
}
static R<int> F3(scoped ref R<int> r3)
{
scoped R<int> l3 = r3;
return l3; // 4
}
}";
var comp = CreateCompilation(source);
comp.VerifyDiagnostics(
// (7,16): error CS8352: Cannot use variable 'l0' in this context because it may expose referenced variables outside of their declaration scope
// return l0; // 1
Diagnostic(ErrorCode.ERR_EscapeVariable, "l0").WithArguments("l0").WithLocation(7, 16),
// (12,16): error CS8352: Cannot use variable 'l1' in this context because it may expose referenced variables outside of their declaration scope
// return l1; // 2
Diagnostic(ErrorCode.ERR_EscapeVariable, "l1").WithArguments("l1").WithLocation(12, 16),
// (17,16): error CS8352: Cannot use variable 'l2' in this context because it may expose referenced variables outside of their declaration scope
// return l2; // 3
Diagnostic(ErrorCode.ERR_EscapeVariable, "l2").WithArguments("l2").WithLocation(17, 16),
// (22,16): error CS8352: Cannot use variable 'l3' in this context because it may expose referenced variables outside of their declaration scope
// return l3; // 4
Diagnostic(ErrorCode.ERR_EscapeVariable, "l3").WithArguments("l3").WithLocation(22, 16));
}
[Fact]
public void RefSafeToEscape_03()
{
var source =
@"ref struct R<T> { }
class Program
{
static ref R<int> F0(R<int> r0)
{
scoped R<int> l0 = r0;
return ref l0; // 1
}
static ref R<int> F1(scoped R<int> r1)
{
scoped R<int> l1 = r1;
return ref l1; // 2
}
static ref R<int> F2(ref R<int> r2)
{
scoped R<int> l2 = r2;
return ref l2; // 3
}
static ref R<int> F3(scoped ref R<int> r3)
{
scoped R<int> l3 = r3;
return ref l3; // 4
}
}";
var comp = CreateCompilation(source);
comp.VerifyDiagnostics(
// (7,20): error CS8168: Cannot return local 'l0' by reference because it is not a ref local
// return ref l0; // 1
Diagnostic(ErrorCode.ERR_RefReturnLocal, "l0").WithArguments("l0").WithLocation(7, 20),
// (12,20): error CS8168: Cannot return local 'l1' by reference because it is not a ref local
// return ref l1; // 2
Diagnostic(ErrorCode.ERR_RefReturnLocal, "l1").WithArguments("l1").WithLocation(12, 20),
// (17,20): error CS8168: Cannot return local 'l2' by reference because it is not a ref local
// return ref l2; // 3
Diagnostic(ErrorCode.ERR_RefReturnLocal, "l2").WithArguments("l2").WithLocation(17, 20),
// (22,20): error CS8168: Cannot return local 'l3' by reference because it is not a ref local
// return ref l3; // 4
Diagnostic(ErrorCode.ERR_RefReturnLocal, "l3").WithArguments("l3").WithLocation(22, 20));
}
[Fact]
public void SafeToEscape_04()
{
var source =
@"ref struct R<T> { }
class Program
{
static R<int> F0(R<int> r0)
{
ref R<int> l0 = ref r0;
return l0;
}
static R<int> F1(scoped R<int> r1)
{
ref R<int> l1 = ref r1;
return l1; // 1
}
static R<int> F2(ref R<int> r2)
{
ref R<int> l2 = ref r2;
return l2;
}
static R<int> F3(scoped ref R<int> r3)
{
ref R<int> l3 = ref r3;
return l3;
}
}";
var comp = CreateCompilation(source);
comp.VerifyDiagnostics(
// (12,16): error CS8352: Cannot use variable 'l1' in this context because it may expose referenced variables outside of their declaration scope
// return l1; // 1
Diagnostic(ErrorCode.ERR_EscapeVariable, "l1").WithArguments("l1").WithLocation(12, 16));
}
[Fact]
public void RefSafeToEscape_04()
{
var source =
@"ref struct R<T> { }
class Program
{
static ref R<int> F0(R<int> r0)
{
ref R<int> l0 = ref r0;
return ref l0; // 1
}
static ref R<int> F1(scoped R<int> r1)
{
ref R<int> l1 = ref r1;
return ref l1; // 2
}
static ref R<int> F2(ref R<int> r2)
{
ref R<int> l2 = ref r2;
return ref l2;
}
static ref R<int> F3(scoped ref R<int> r3)
{
ref R<int> l3 = ref r3;
return ref l3; // 3
}
}";
var comp = CreateCompilation(source);
comp.VerifyDiagnostics(
// (7,20): error CS8157: Cannot return 'l0' by reference because it was initialized to a value that cannot be returned by reference
// return ref l0; // 1
Diagnostic(ErrorCode.ERR_RefReturnNonreturnableLocal, "l0").WithArguments("l0").WithLocation(7, 20),
// (12,20): error CS8157: Cannot return 'l1' by reference because it was initialized to a value that cannot be returned by reference
// return ref l1; // 2
Diagnostic(ErrorCode.ERR_RefReturnNonreturnableLocal, "l1").WithArguments("l1").WithLocation(12, 20),
// (22,20): error CS8157: Cannot return 'l3' by reference because it was initialized to a value that cannot be returned by reference
// return ref l3; // 3
Diagnostic(ErrorCode.ERR_RefReturnNonreturnableLocal, "l3").WithArguments("l3").WithLocation(22, 20));
}
[Fact]
public void SafeToEscape_05()
{
var source =
@"ref struct R<T> { }
class Program
{
static R<int> F0(R<int> r0)
{
scoped ref R<int> l0 = ref r0;
return l0;
}
static R<int> F1(scoped R<int> r1)
{
scoped ref R<int> l1 = ref r1; // 1
return l1;
}
static R<int> F2(ref R<int> r2)
{
scoped ref R<int> l2 = ref r2;
return l2;
}
}";
var comp = CreateCompilation(source);
comp.VerifyDiagnostics(
// (11,36): error CS8352: Cannot use variable 'scoped R<int> r1' in this context because it may expose referenced variables outside of their declaration scope
// scoped ref R<int> l1 = ref r1; // 1
Diagnostic(ErrorCode.ERR_EscapeVariable, "r1").WithArguments("scoped R<int> r1").WithLocation(11, 36));
}
[Fact]
public void RefSafeToEscape_05()
{
var source =
@"ref struct R<T> { }
class Program
{
static ref R<int> F0(R<int> r0)
{
scoped ref R<int> l0 = ref r0;
return ref l0; // 1
}
static ref R<int> F1(scoped R<int> r1)
{
scoped ref R<int> l1 = ref r1; // 2
return ref l1; // 3
}
static ref R<int> F2(ref R<int> r2)
{
scoped ref R<int> l2 = ref r2;
return ref l2; // 4
}
static ref R<int> F3(scoped ref R<int> r3)
{
scoped ref R<int> l3 = ref r3;
return ref l3; // 5
}
}";
var comp = CreateCompilation(source);
comp.VerifyDiagnostics(
// (7,20): error CS8157: Cannot return 'l0' by reference because it was initialized to a value that cannot be returned by reference
// return ref l0; // 1
Diagnostic(ErrorCode.ERR_RefReturnNonreturnableLocal, "l0").WithArguments("l0").WithLocation(7, 20),
// (11,36): error CS8352: Cannot use variable 'scoped R<int> r1' in this context because it may expose referenced variables outside of their declaration scope
// scoped ref R<int> l1 = ref r1; // 2
Diagnostic(ErrorCode.ERR_EscapeVariable, "r1").WithArguments("scoped R<int> r1").WithLocation(11, 36),
// (12,20): error CS8157: Cannot return 'l1' by reference because it was initialized to a value that cannot be returned by reference
// return ref l1; // 3
Diagnostic(ErrorCode.ERR_RefReturnNonreturnableLocal, "l1").WithArguments("l1").WithLocation(12, 20),
// (17,20): error CS8157: Cannot return 'l2' by reference because it was initialized to a value that cannot be returned by reference
// return ref l2; // 4
Diagnostic(ErrorCode.ERR_RefReturnNonreturnableLocal, "l2").WithArguments("l2").WithLocation(17, 20),
// (22,20): error CS8157: Cannot return 'l3' by reference because it was initialized to a value that cannot be returned by reference
// return ref l3; // 5
Diagnostic(ErrorCode.ERR_RefReturnNonreturnableLocal, "l3").WithArguments("l3").WithLocation(22, 20));
}
[Fact]
public void ReturnValueField_01()
{
var source =
@"ref struct R<T>
{
public T F;
public T GetValue() => F;
public ref T GetRef() => ref F; // 1
public ref readonly T GetRefReadonly() => ref F; // 2
}";
var comp = CreateCompilation(source);
comp.VerifyDiagnostics(
// (5,34): error CS8170: Struct members cannot return 'this' or other instance members by reference
// public ref T GetRef() => ref F; // 1
Diagnostic(ErrorCode.ERR_RefReturnStructThis, "F").WithLocation(5, 34),
// (6,51): error CS8170: Struct members cannot return 'this' or other instance members by reference
// public ref readonly T GetRefReadonly() => ref F; // 2
Diagnostic(ErrorCode.ERR_RefReturnStructThis, "F").WithLocation(6, 51));
}
[Fact]
public void ReturnValueField_02()
{
var source =
@"struct S<T>
{
public T F;
public T GetValue() => F;
public ref T GetRef() => ref F; // 1
public ref readonly T GetRefReadonly() => ref F; // 2
}";
var comp = CreateCompilation(source);
comp.VerifyDiagnostics(
// (5,34): error CS8170: Struct members cannot return 'this' or other instance members by reference
// public ref T GetRef() => ref F; // 1
Diagnostic(ErrorCode.ERR_RefReturnStructThis, "F").WithLocation(5, 34),
// (6,51): error CS8170: Struct members cannot return 'this' or other instance members by reference
// public ref readonly T GetRefReadonly() => ref F; // 2
Diagnostic(ErrorCode.ERR_RefReturnStructThis, "F").WithLocation(6, 51));
}
[Fact]
public void ReturnRefField()
{
var source =
@"ref struct R<T>
{
public ref T F;
public T GetValue() => F;
public ref T GetRef() => ref F;
public ref readonly T GetRefReadonly() => ref F;
}";
var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70);
comp.VerifyDiagnostics();
}
[Fact]
public void ReturnRefReadonlyField()
{
var source =
@"ref struct R<T>
{
public ref readonly T F;
public T GetValue() => F;
public ref T GetRef() => ref F; // 1
public ref readonly T GetRefReadonly() => ref F;
}";
var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70);
comp.VerifyDiagnostics(
// (5,34): error CS8333: Cannot return field 'F' by writable reference because it is a readonly variable
// public ref T GetRef() => ref F; // 1
Diagnostic(ErrorCode.ERR_RefReturnReadonlyNotField, "F").WithArguments("field", "F").WithLocation(5, 34));
}
[Fact]
public void ReturnValueFieldByValue()
{
var source =
@"#pragma warning disable 649
ref struct R<T>
{
public T F;
}
class Program
{
static T F0<T>(R<T> r0) => r0.F;
static T F1<T>(scoped R<T> r1) => r1.F;
static T F2<T>(ref R<T> r2) => r2.F;
static T F3<T>(scoped ref R<T> r3) => r3.F;
}";
var comp = CreateCompilation(source);
comp.VerifyDiagnostics();
}
[Fact]
public void ReturnValueFieldByRef()
{
var source =
@"ref struct R<T>
{
public T F;
}
class Program
{
static ref T F0<T>(R<T> r0) => ref r0.F; // 1
static ref T F1<T>(scoped R<T> r1) => ref r1.F; // 2
static ref T F2<T>(ref R<T> r2) => ref r2.F;
static ref T F3<T>(scoped ref R<T> r3) => ref r3.F; // 3
}";
var comp = CreateCompilation(source);
comp.VerifyDiagnostics(
// (7,40): error CS8167: Cannot return by reference a member of parameter 'r0' because it is not a ref or out parameter
// static ref T F0<T>(R<T> r0) => ref r0.F; // 1
Diagnostic(ErrorCode.ERR_RefReturnParameter2, "r0").WithArguments("r0").WithLocation(7, 40),
// (8,47): error CS8167: Cannot return by reference a member of parameter 'r1' because it is not a ref or out parameter
// static ref T F1<T>(scoped R<T> r1) => ref r1.F; // 2
Diagnostic(ErrorCode.ERR_RefReturnParameter2, "r1").WithArguments("r1").WithLocation(8, 47),
// (10,51): error CS9076: Cannot return by reference a member of parameter 'r3' because it is scoped to the current method
// static ref T F3<T>(scoped ref R<T> r3) => ref r3.F; // 3
Diagnostic(ErrorCode.ERR_RefReturnScopedParameter2, "r3").WithArguments("r3").WithLocation(10, 51));
// https://github.com/dotnet/roslyn/issues/62780: Test additional cases with [UnscopedRef].
}
[Fact]
public void RefAssignMemberOfReturnOnlyParameter()
{
var source = @"
ref struct RS1
{
public int I1;
}
ref struct RS2
{
public ref int I2;
}
class Program
{
static void M(ref RS1 rs, ref RS2 rs2)
{
rs2 = new RS2 { I2 = ref rs.I1 };
}
}";
var comp = CreateCompilation(new[] { source, UnscopedRefAttributeDefinition }, targetFramework: TargetFramework.Net70);
comp.VerifyDiagnostics(
// (16,34): error CS9078: Cannot return by reference a member of parameter 'rs' through a ref parameter; it can only be returned in a return statement
// rs2 = new RS2 { I2 = ref rs.I1 };
Diagnostic(ErrorCode.ERR_RefReturnOnlyParameter2, "rs").WithArguments("rs").WithLocation(16, 34)
);
}
[Fact]
public void RefAssignMemberOfReturnOnlyParameter_UnsafeContext()
{
var source = @"
ref struct RS1
{
public int I1;
}
ref struct RS2
{
public ref int I2;
}
class Program
{
static unsafe void M(ref RS1 rs, ref RS2 rs2)
{
rs2 = new RS2 { I2 = ref rs.I1 };
}
}";
var comp = CreateCompilation(new[] { source, UnscopedRefAttributeDefinition }, targetFramework: TargetFramework.Net70, options: TestOptions.UnsafeDebugDll);
comp.VerifyDiagnostics(
// (16,34): warning CS9095: This returns by reference a member of parameter 'rs' through a ref parameter; but it can only safely be returned in a return statement
// rs2 = new RS2 { I2 = ref rs.I1 };
Diagnostic(ErrorCode.WRN_RefReturnOnlyParameter2, "rs").WithArguments("rs").WithLocation(16, 34)
);
}
[Fact]
public void ReturnValueFieldByRef_UnsafeContext()
{
var source =
@"ref struct R<T>
{
public T F;
}
unsafe class Program
{
static ref T F0<T>(R<T> r0) => ref r0.F; // 1
static ref T F1<T>(scoped R<T> r1) => ref r1.F; // 2
static ref T F2<T>(ref R<T> r2) => ref r2.F;
static ref T F3<T>(scoped ref R<T> r3) => ref r3.F; // 3
}";
var comp = CreateCompilation(source, options: TestOptions.UnsafeDebugDll);
comp.VerifyDiagnostics(
// (7,40): warning CS9089: This returns by reference a member of parameter 'r0' that is not a ref or out parameter
// static ref T F0<T>(R<T> r0) => ref r0.F; // 1
Diagnostic(ErrorCode.WRN_RefReturnParameter2, "r0").WithArguments("r0").WithLocation(7, 40),
// (8,47): warning CS9089: This returns by reference a member of parameter 'r1' that is not a ref or out parameter
// static ref T F1<T>(scoped R<T> r1) => ref r1.F; // 2
Diagnostic(ErrorCode.WRN_RefReturnParameter2, "r1").WithArguments("r1").WithLocation(8, 47),
// (10,51): warning CS9090: This returns by reference a member of parameter 'r3' that is scoped to the current method
// static ref T F3<T>(scoped ref R<T> r3) => ref r3.F; // 3
Diagnostic(ErrorCode.WRN_RefReturnScopedParameter2, "r3").WithArguments("r3").WithLocation(10, 51));
var verifier = CompileAndVerify(comp, verify: Verification.Skipped);
verifier.VerifyIL("Program.F0<T>", @"
{
// Code size 8 (0x8)
.maxstack 1
IL_0000: ldarga.s V_0
IL_0002: ldflda ""T R<T>.F""
IL_0007: ret
}
");
verifier.VerifyIL("Program.F2<T>", @"
{
// Code size 7 (0x7)
.maxstack 1
IL_0000: ldarg.0
IL_0001: ldflda ""T R<T>.F""
IL_0006: ret
}
");
}
[Theory]
[InlineData("ref ")]
[InlineData("ref readonly")]
public void ReturnRefFieldByValue(string refOrRefReadonly)
{
var source =
$@"ref struct R<T>
{{
public {refOrRefReadonly} T F;
public R(ref T t) {{ F = ref t; }}
}}
class Program
{{
static T F0<T>(R<T> r) => r.F;
static T F1<T>(ref R<T> r) => r.F;
static T F2<T>(out R<T> r) {{ r = default; return r.F; }}
static T F3<T>(in R<T> r) => r.F;
static T F4<T>(scoped R<T> r) => r.F;
static T F5<T>(scoped ref R<T> r) => r.F;
static T F6<T>(scoped out R<T> r) {{ r = default; return r.F; }}
static T F7<T>(scoped in R<T> r) => r.F;
}}";
var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70);
comp.VerifyDiagnostics();
}
[Theory]
[InlineData("ref ")]
[InlineData("ref readonly")]
public void ReturnRefFieldByRef_01(string refOrRefReadonly)
{
var source =
$@"ref struct R<T>
{{
public {refOrRefReadonly} T F;
public R(ref T t) {{ F = ref t; }}
}}
class Program
{{
static {refOrRefReadonly} T F0<T>(R<T> r) => ref r.F;
static {refOrRefReadonly} T F1<T>(ref R<T> r) => ref r.F;
static {refOrRefReadonly} T F2<T>(out R<T> r) {{ r = default; return ref r.F; }}
static {refOrRefReadonly} T F3<T>(in R<T> r) => ref r.F;
static {refOrRefReadonly} T F4<T>(scoped R<T> r) => ref r.F; // 1
static {refOrRefReadonly} T F5<T>(scoped ref R<T> r) => ref r.F;
static {refOrRefReadonly} T F6<T>(scoped out R<T> r) {{ r = default; return ref r.F; }}
static {refOrRefReadonly} T F7<T>(scoped in R<T> r) => ref r.F;
}}";
var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70);
comp.VerifyDiagnostics(
// (12,55): error CS8352: Cannot use variable 'scoped R<T> r' in this context because it may expose referenced variables outside of their declaration scope
// static ref T F4<T>(scoped R<T> r) => ref r.F; // 1
Diagnostic(ErrorCode.ERR_EscapeVariable, "r.F").WithArguments("scoped R<T> r").WithLocation(12, 55));
}
[Fact]
public void ReturnRefFieldByRef_02()
{
var source =
@"ref struct R<T>
{
public ref readonly T F;
public R(ref T t) { F = ref t; }
}
class Program
{
static ref readonly T F1<T>(scoped ref T t)
{
R<T> r1 = new R<T>(ref t);
return ref r1.F; // 1
}
static ref readonly T F2<T>(scoped ref T t)
{
R<T> r2;
r2 = new R<T>(ref t); // 2
return ref r2.F;
}
}";
var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70);
comp.VerifyDiagnostics(
// (11,20): error CS8352: Cannot use variable 'r1' in this context because it may expose referenced variables outside of their declaration scope
// return ref r1.F; // 1
Diagnostic(ErrorCode.ERR_EscapeVariable, "r1.F").WithArguments("r1").WithLocation(11, 20),
// (16,14): error CS8347: Cannot use a result of 'R<T>.R(ref T)' in this context because it may expose variables referenced by parameter 't' outside of their declaration scope
// r2 = new R<T>(ref t); // 2
Diagnostic(ErrorCode.ERR_EscapeCall, "new R<T>(ref t)").WithArguments("R<T>.R(ref T)", "t").WithLocation(16, 14),
// (16,27): error CS9075: Cannot return a parameter by reference 't' because it is scoped to the current method
// r2 = new R<T>(ref t); // 2
Diagnostic(ErrorCode.ERR_RefReturnScopedParameter, "t").WithArguments("t").WithLocation(16, 27));
}
[Fact]
public void ReturnRefFieldByRef_03()
{
var source =
@"ref struct R<T>
{
public ref readonly T F;
public R(in T t) { F = ref t; }
}
class Program
{
static ref readonly T F1<T>(scoped in T t)
{
R<T> r1 = new R<T>(t);
return ref r1.F; // 1
}
static ref readonly T F2<T>(scoped in T t)
{
R<T> r2 = new R<T>(in t);
return ref r2.F; // 2
}
}";
var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70);
comp.VerifyDiagnostics(
// (11,20): error CS8352: Cannot use variable 'r1' in this context because it may expose referenced variables outside of their declaration scope
// return ref r1.F; // 1
Diagnostic(ErrorCode.ERR_EscapeVariable, "r1.F").WithArguments("r1").WithLocation(11, 20),
// (16,20): error CS8352: Cannot use variable 'r2' in this context because it may expose referenced variables outside of their declaration scope
// return ref r2.F; // 2
Diagnostic(ErrorCode.ERR_EscapeVariable, "r2.F").WithArguments("r2").WithLocation(16, 20));
}
[Fact]
public void ReturnRefStructFieldByValue_01()
{
var source =
@"ref struct R<T>
{
public ref T F;
public R(ref T t) { F = ref t; }
}
class Program
{
static R<T> F1<T>(ref T t) => new R<T>(ref t);
static R<T> F2<T>(out T t, T tValue) { t = tValue; return new R<T>(ref t); } // 1
static R<T> F3<T>(scoped ref T t) => new R<T>(ref t); // 2
static R<T> F4<T>(scoped out T t, T tValue) { t = tValue; return new R<T>(ref t); } // 3
}";
var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70);
comp.VerifyDiagnostics(
// (9,63): error CS8347: Cannot use a result of 'R<T>.R(ref T)' in this context because it may expose variables referenced by parameter 't' outside of their declaration scope
// static R<T> F2<T>(out T t, T tValue) { t = tValue; return new R<T>(ref t); } // 1
Diagnostic(ErrorCode.ERR_EscapeCall, "new R<T>(ref t)").WithArguments("R<T>.R(ref T)", "t").WithLocation(9, 63),
// (9,76): error CS9075: Cannot return a parameter by reference 't' because it is scoped to the current method
// static R<T> F2<T>(out T t, T tValue) { t = tValue; return new R<T>(ref t); } // 1
Diagnostic(ErrorCode.ERR_RefReturnScopedParameter, "t").WithArguments("t").WithLocation(9, 76),
// (10,42): error CS8347: Cannot use a result of 'R<T>.R(ref T)' in this context because it may expose variables referenced by parameter 't' outside of their declaration scope
// static R<T> F3<T>(scoped ref T t) => new R<T>(ref t); // 2
Diagnostic(ErrorCode.ERR_EscapeCall, "new R<T>(ref t)").WithArguments("R<T>.R(ref T)", "t").WithLocation(10, 42),
// (10,55): error CS9075: Cannot return a parameter by reference 't' because it is scoped to the current method
// static R<T> F3<T>(scoped ref T t) => new R<T>(ref t); // 2
Diagnostic(ErrorCode.ERR_RefReturnScopedParameter, "t").WithArguments("t").WithLocation(10, 55),
// (11,70): error CS8347: Cannot use a result of 'R<T>.R(ref T)' in this context because it may expose variables referenced by parameter 't' outside of their declaration scope
// static R<T> F4<T>(scoped out T t, T tValue) { t = tValue; return new R<T>(ref t); } // 3
Diagnostic(ErrorCode.ERR_EscapeCall, "new R<T>(ref t)").WithArguments("R<T>.R(ref T)", "t").WithLocation(11, 70),
// (11,83): error CS9075: Cannot return a parameter by reference 't' because it is scoped to the current method
// static R<T> F4<T>(scoped out T t, T tValue) { t = tValue; return new R<T>(ref t); } // 3
Diagnostic(ErrorCode.ERR_RefReturnScopedParameter, "t").WithArguments("t").WithLocation(11, 83));
}
[Fact]
public void ReturnRefStructFieldByValue_02()
{
var source =
@"ref struct R0<T>
{
public ref T F0;
public R0(ref T t) { F0 = ref t; }
}
ref struct R1<T>
{
public R0<T> F1;
public R1(ref T t) { F1 = new R0<T>(ref t); }
}
class Program
{
static R0<T> F0<T>(R1<T> r0) => r0.F1;
static R0<T> F1<T>(scoped R1<T> r1) => r1.F1; // 1
static R0<T> F2<T>(ref R1<T> r2) => r2.F1;
static R0<T> F3<T>(scoped ref R1<T> r3) => r3.F1;
}";
var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70);
comp.VerifyDiagnostics(
// (14,44): error CS8352: Cannot use variable 'scoped R1<T> r1' in this context because it may expose referenced variables outside of their declaration scope
// static R0<T> F1<T>(scoped R1<T> r1) => r1.F1; // 1
Diagnostic(ErrorCode.ERR_EscapeVariable, "r1.F1").WithArguments("scoped R1<T> r1").WithLocation(14, 44));
}
[Fact]
public void ReturnRefStructFieldByRef()
{
var source =
@"ref struct R0<T>
{
public ref T F0;
public R0(ref T t) { F0 = ref t; }
}
ref struct R1<T>
{
public R0<T> F1;
public R1(ref T t) { F1 = new R0<T>(ref t); }
}
class Program
{
static ref R0<T> F0<T>(R1<T> r0) => ref r0.F1; // 1
static ref R0<T> F1<T>(scoped R1<T> r1) => ref r1.F1; // 2
static ref R0<T> F2<T>(ref R1<T> r2) => ref r2.F1;
static ref R0<T> F3<T>(scoped ref R1<T> r3) => ref r3.F1; // 3
}";
var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70);
comp.VerifyDiagnostics(
// (13,45): error CS8167: Cannot return by reference a member of parameter 'r0' because it is not a ref or out parameter
// static ref R0<T> F0<T>(R1<T> r0) => ref r0.F1; // 1
Diagnostic(ErrorCode.ERR_RefReturnParameter2, "r0").WithArguments("r0").WithLocation(13, 45),
// (14,52): error CS8167: Cannot return by reference a member of parameter 'r1' because it is not a ref or out parameter
// static ref R0<T> F1<T>(scoped R1<T> r1) => ref r1.F1; // 2
Diagnostic(ErrorCode.ERR_RefReturnParameter2, "r1").WithArguments("r1").WithLocation(14, 52),
// (16,56): error CS9076: Cannot return by reference a member of parameter 'r3' because it is scoped to the current method
// static ref R0<T> F3<T>(scoped ref R1<T> r3) => ref r3.F1; // 3
Diagnostic(ErrorCode.ERR_RefReturnScopedParameter2, "r3").WithArguments("r3").WithLocation(16, 56));
}
[Fact]
public void ReturnRefFieldFromCaller()
{
var source =
@"ref struct R<T>
{
public ref T F;
public R(ref T t) { F = ref t; }
}
class Program
{
static ref T F0<T>(R<T> r0)
{
return ref r0.F;
}
static ref T F1<T>()
{
return ref F0(new R<T>()); // ok, returns null
}
static ref T F2<T>()
{
T t = default;
return ref F0(new R<T>(ref t)); // error
}
}";
var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70);
comp.VerifyDiagnostics(
// (19,20): error CS8347: Cannot use a result of 'Program.F0<T>(R<T>)' in this context because it may expose variables referenced by parameter 'r0' outside of their declaration scope
// return ref F0(new R<T>(ref t)); // error
Diagnostic(ErrorCode.ERR_EscapeCall, "F0(new R<T>(ref t))").WithArguments("Program.F0<T>(R<T>)", "r0").WithLocation(19, 20),
// (19,23): error CS8347: Cannot use a result of 'R<T>.R(ref T)' in this context because it may expose variables referenced by parameter 't' outside of their declaration scope
// return ref F0(new R<T>(ref t)); // error
Diagnostic(ErrorCode.ERR_EscapeCall, "new R<T>(ref t)").WithArguments("R<T>.R(ref T)", "t").WithLocation(19, 23),
// (19,36): error CS8168: Cannot return local 't' by reference because it is not a ref local
// return ref F0(new R<T>(ref t)); // error
Diagnostic(ErrorCode.ERR_RefReturnLocal, "t").WithArguments("t").WithLocation(19, 36));
}
[Fact]
public void PropertyReturnValue_01()
{
var source =
@"ref struct R
{
private ref int _i;
public R(ref int i) { _i = ref i; }
}
class C
{
R this[R x, R y] => x;
R F1(R x1, R y1)
{
return this[x1, y1];
}
R F2(R x2)
{
int i2 = 0;
return this[x2, new R(ref i2)]; // 1
}
static R F3(C c, R x3, R y3)
{
return c[x3, y3];
}
static R F4(C c, R y4)
{
int i4 = 0;
return c[new R(ref i4), y4]; // 2
}
}";
var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70);
comp.VerifyDiagnostics(
// (16,16): error CS8347: Cannot use a result of 'C.this[R, R]' in this context because it may expose variables referenced by parameter 'y' outside of their declaration scope
// return this[x2, new R(ref i2)]; // 1
Diagnostic(ErrorCode.ERR_EscapeCall, "this[x2, new R(ref i2)]").WithArguments("C.this[R, R]", "y").WithLocation(16, 16),
// (16,25): error CS8347: Cannot use a result of 'R.R(ref int)' in this context because it may expose variables referenced by parameter 'i' outside of their declaration scope
// return this[x2, new R(ref i2)]; // 1
Diagnostic(ErrorCode.ERR_EscapeCall, "new R(ref i2)").WithArguments("R.R(ref int)", "i").WithLocation(16, 25),
// (16,35): error CS8168: Cannot return local 'i2' by reference because it is not a ref local
// return this[x2, new R(ref i2)]; // 1
Diagnostic(ErrorCode.ERR_RefReturnLocal, "i2").WithArguments("i2").WithLocation(16, 35),
// (25,16): error CS8347: Cannot use a result of 'C.this[R, R]' in this context because it may expose variables referenced by parameter 'x' outside of their declaration scope
// return c[new R(ref i4), y4]; // 2
Diagnostic(ErrorCode.ERR_EscapeCall, "c[new R(ref i4), y4]").WithArguments("C.this[R, R]", "x").WithLocation(25, 16),
// (25,18): error CS8347: Cannot use a result of 'R.R(ref int)' in this context because it may expose variables referenced by parameter 'i' outside of their declaration scope
// return c[new R(ref i4), y4]; // 2
Diagnostic(ErrorCode.ERR_EscapeCall, "new R(ref i4)").WithArguments("R.R(ref int)", "i").WithLocation(25, 18),
// (25,28): error CS8168: Cannot return local 'i4' by reference because it is not a ref local
// return c[new R(ref i4), y4]; // 2
Diagnostic(ErrorCode.ERR_RefReturnLocal, "i4").WithArguments("i4").WithLocation(25, 28));
}
[Fact]
public void PropertyReturnValue_02()
{
var source =
@"ref struct R
{
private ref readonly int _i;
public R(in int i) { _i = ref i; }
}
class C
{
R this[in int x, in int y] => new R(x);
R F1(in int x1, in int y1)
{
return this[x1, y1];
}
R F2(in int x2)
{
int y2 = 0;
return this[x2, y2]; // 1
}
static R F3(C c, in int x3, in int y3)
{
return c[x3, y3];
}
static R F4(C c, in int y4)
{
int x4 = 0;
return c[x4, y4]; // 2
}
}";
var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70);
comp.VerifyDiagnostics(
// (16,16): error CS8347: Cannot use a result of 'C.this[in int, in int]' in this context because it may expose variables referenced by parameter 'y' outside of their declaration scope
// return this[x2, y2]; // 1
Diagnostic(ErrorCode.ERR_EscapeCall, "this[x2, y2]").WithArguments("C.this[in int, in int]", "y").WithLocation(16, 16),
// (16,25): error CS8168: Cannot return local 'y2' by reference because it is not a ref local
// return this[x2, y2]; // 1
Diagnostic(ErrorCode.ERR_RefReturnLocal, "y2").WithArguments("y2").WithLocation(16, 25),
// (25,16): error CS8347: Cannot use a result of 'C.this[in int, in int]' in this context because it may expose variables referenced by parameter 'x' outside of their declaration scope
// return c[x4, y4]; // 2
Diagnostic(ErrorCode.ERR_EscapeCall, "c[x4, y4]").WithArguments("C.this[in int, in int]", "x").WithLocation(25, 16),
// (25,18): error CS8168: Cannot return local 'x4' by reference because it is not a ref local
// return c[x4, y4]; // 2
Diagnostic(ErrorCode.ERR_RefReturnLocal, "x4").WithArguments("x4").WithLocation(25, 18));
}
[Fact]
public void PropertyReturnValue_03()
{
var source =
@"ref struct R
{
public ref int _i;
public R(ref int i) { _i = ref i; }
}
class C
{
ref int this[R x, R y] => ref x._i;
ref int F1(R x1, R y1)
{
return ref this[x1, y1];
}
ref int F2(R x2)
{
int i2 = 0;
return ref this[x2, new R(ref i2)]; // 1
}
static ref int F3(C c, R x3, R y3)
{
return ref c[x3, y3];
}
static ref int F4(C c, R y4)
{
int i4 = 0;
return ref c[new R(ref i4), y4]; // 2
}
}";
var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70);
comp.VerifyDiagnostics(
// (16,20): error CS8347: Cannot use a result of 'C.this[R, R]' in this context because it may expose variables referenced by parameter 'y' outside of their declaration scope
// return ref this[x2, new R(ref i2)]; // 1
Diagnostic(ErrorCode.ERR_EscapeCall, "this[x2, new R(ref i2)]").WithArguments("C.this[R, R]", "y").WithLocation(16, 20),
// (16,29): error CS8347: Cannot use a result of 'R.R(ref int)' in this context because it may expose variables referenced by parameter 'i' outside of their declaration scope
// return ref this[x2, new R(ref i2)]; // 1
Diagnostic(ErrorCode.ERR_EscapeCall, "new R(ref i2)").WithArguments("R.R(ref int)", "i").WithLocation(16, 29),
// (16,39): error CS8168: Cannot return local 'i2' by reference because it is not a ref local
// return ref this[x2, new R(ref i2)]; // 1
Diagnostic(ErrorCode.ERR_RefReturnLocal, "i2").WithArguments("i2").WithLocation(16, 39),
// (25,20): error CS8347: Cannot use a result of 'C.this[R, R]' in this context because it may expose variables referenced by parameter 'x' outside of their declaration scope
// return ref c[new R(ref i4), y4]; // 2
Diagnostic(ErrorCode.ERR_EscapeCall, "c[new R(ref i4), y4]").WithArguments("C.this[R, R]", "x").WithLocation(25, 20),
// (25,22): error CS8347: Cannot use a result of 'R.R(ref int)' in this context because it may expose variables referenced by parameter 'i' outside of their declaration scope
// return ref c[new R(ref i4), y4]; // 2
Diagnostic(ErrorCode.ERR_EscapeCall, "new R(ref i4)").WithArguments("R.R(ref int)", "i").WithLocation(25, 22),
// (25,32): error CS8168: Cannot return local 'i4' by reference because it is not a ref local
// return ref c[new R(ref i4), y4]; // 2
Diagnostic(ErrorCode.ERR_RefReturnLocal, "i4").WithArguments("i4").WithLocation(25, 32));
}
[Fact]
public void PropertyReturnValue_04()
{
var source =
@"class C
{
ref readonly int this[in int x, in int y] => ref x;
ref readonly int F1(in int x1, in int y1)
{
return ref this[x1, y1];
}
ref readonly int F2(in int x2)
{
int y2 = 0;
return ref this[x2, y2]; // 1
}
static ref readonly int F3(C c, in int x3, in int y3)
{
return ref c[x3, y3];
}
static ref readonly int F4(C c, in int y4)
{
int x4 = 0;
return ref c[x4, y4]; // 2
}
}";
var comp = CreateCompilation(source);
comp.VerifyDiagnostics(
// (11,20): error CS8347: Cannot use a result of 'C.this[in int, in int]' in this context because it may expose variables referenced by parameter 'y' outside of their declaration scope
// return ref this[x2, y2]; // 1
Diagnostic(ErrorCode.ERR_EscapeCall, "this[x2, y2]").WithArguments("C.this[in int, in int]", "y").WithLocation(11, 20),
// (11,29): error CS8168: Cannot return local 'y2' by reference because it is not a ref local
// return ref this[x2, y2]; // 1
Diagnostic(ErrorCode.ERR_RefReturnLocal, "y2").WithArguments("y2").WithLocation(11, 29),
// (20,20): error CS8347: Cannot use a result of 'C.this[in int, in int]' in this context because it may expose variables referenced by parameter 'x' outside of their declaration scope
// return ref c[x4, y4]; // 2
Diagnostic(ErrorCode.ERR_EscapeCall, "c[x4, y4]").WithArguments("C.this[in int, in int]", "x").WithLocation(20, 20),
// (20,22): error CS8168: Cannot return local 'x4' by reference because it is not a ref local
// return ref c[x4, y4]; // 2
Diagnostic(ErrorCode.ERR_RefReturnLocal, "x4").WithArguments("x4").WithLocation(20, 22));
}
[Fact]
public void RefStructLocal_FromLocal_01()
{
var source =
@"ref struct R<T>
{
public ref T F;
public R(ref T t) { F = ref t; }
}
class Program
{
static R<T> Create<T>() => new R<T>();
static R<T> Create<T>(ref T t) => new R<T>(ref t);
static void F<T>(T t) { }
static T F1<T>()
{
T t = default;
R<T> r1 = new R<T>(ref t);
F(r1.F);
return r1.F;
}
static T F2<T>()
{
T t = default;
scoped R<T> r2 = new R<T>(ref t);
F(r2.F);
return r2.F;
}
static T F3<T>()
{
T t = default;
R<T> r3 = new R<T>();
r3.F = ref t;
F(r3.F);
return r3.F;
}
static T F4<T>()
{
T t = default;
scoped R<T> r4 = new R<T>();
r4.F = ref t;
F(r4.F);
return r4.F;
}
static T F5<T>()
{
T t = default;
R<T> r5 = Create(ref t);
F(r5.F);
return r5.F;
}
static T F6<T>()
{
T t = default;
scoped R<T> r6 = Create(ref t);
F(r6.F);
return r6.F;
}
static T F7<T>()
{
T t = default;
R<T> r7 = Create<T>();
r7.F = ref t;
F(r7.F);
return r7.F;
}
static T F8<T>()
{
T t = default;
scoped R<T> r8 = Create<T>();
r8.F = ref t;
F(r8.F);
return r8.F;
}
}";
var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70);
comp.VerifyEmitDiagnostics(
// (29,9): error CS8374: Cannot ref-assign 't' to 'F' because 't' has a narrower escape scope than 'F'.
// r3.F = ref t;
Diagnostic(ErrorCode.ERR_RefAssignNarrower, "r3.F = ref t").WithArguments("F", "t").WithLocation(29, 9),
// (59,9): error CS8374: Cannot ref-assign 't' to 'F' because 't' has a narrower escape scope than 'F'.
// r7.F = ref t;
Diagnostic(ErrorCode.ERR_RefAssignNarrower, "r7.F = ref t").WithArguments("F", "t").WithLocation(59, 9)
);
}
[Fact]
public void RefStructLocal_FromParameter_01()
{
var source =
@"ref struct R<T>
{
public ref T F;
public R(ref T t) { F = ref t; }
}
class Program
{
static R<T> Create<T>() => new R<T>();
static R<T> Create<T>(ref T t) => new R<T>(ref t);
static void F<T>(T t) { }
static T F1<T>(T t)
{
R<T> r1 = new R<T>(ref t);
F(r1.F);
return r1.F;
}
static T F2<T>(T t)
{
scoped R<T> r2 = new R<T>(ref t);
F(r2.F);
return r2.F;
}
static T F3<T>(T t)
{
R<T> r3 = new R<T>();
r3.F = ref t;
F(r3.F);
return r3.F;
}
static T F4<T>(T t)
{
scoped R<T> r4 = new R<T>();
r4.F = ref t;
F(r4.F);
return r4.F;
}
static T F5<T>(T t)
{
R<T> r5 = Create(ref t);
F(r5.F);
return r5.F;
}
static T F6<T>(T t)
{
scoped R<T> r6 = Create(ref t);
F(r6.F);
return r6.F;
}
static T F7<T>(T t)
{
R<T> r7 = Create<T>();
r7.F = ref t;
F(r7.F);
return r7.F;
}
static T F8<T>(T t)
{
scoped R<T> r8 = Create<T>();
r8.F = ref t;
F(r8.F);
return r8.F;
}
}";
var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70);
comp.VerifyEmitDiagnostics(
// (26,9): error CS8374: Cannot ref-assign 't' to 'F' because 't' has a narrower escape scope than 'F'.
// r3.F = ref t;
Diagnostic(ErrorCode.ERR_RefAssignNarrower, "r3.F = ref t").WithArguments("F", "t").WithLocation(26, 9),
// (52,9): error CS8374: Cannot ref-assign 't' to 'F' because 't' has a narrower escape scope than 'F'.
// r7.F = ref t;
Diagnostic(ErrorCode.ERR_RefAssignNarrower, "r7.F = ref t").WithArguments("F", "t").WithLocation(52, 9));
}
[Fact]
public void RefStructLocal_FromLocal_02()
{
var source =
@"ref struct R<T>
{
public ref T F;
public R(ref T t) { F = ref t; }
}
class Program
{
static R<T> Create<T>() => new R<T>();
static R<T> Create<T>(ref T t) => new R<T>(ref t);
static void F<T>(R<T> r) { }
static R<T> F1<T>()
{
T t = default;
R<T> r1 = new R<T>(ref t);
F(r1);
return r1;
}
static R<T> F2<T>()
{
T t = default;
scoped R<T> r2 = new R<T>(ref t);
F(r2);
return r2;
}
static R<T> F3<T>()
{
T t = default;
R<T> r3 = new R<T>();
r3.F = ref t;
F(r3);
return r3;
}
static R<T> F4<T>()
{
T t = default;
scoped R<T> r4 = new R<T>();
r4.F = ref t;
F(r4);
return r4;
}
static R<T> F5<T>()
{
T t = default;
R<T> r5 = Create(ref t);
F(r5);
return r5;
}
static R<T> F6<T>()
{
T t = default;
scoped R<T> r6 = Create(ref t);
F(r6);
return r6;
}
static R<T> F7<T>()
{
T t = default;
R<T> r7 = Create<T>();
r7.F = ref t;
F(r7);
return r7;
}
static R<T> F8<T>()
{
T t = default;
scoped R<T> r8 = Create<T>();
r8.F = ref t;
F(r8);
return r8;
}
}";
var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70);
comp.VerifyEmitDiagnostics(
// (16,16): error CS8352: Cannot use variable 'r1' in this context because it may expose referenced variables outside of their declaration scope
// return r1;
Diagnostic(ErrorCode.ERR_EscapeVariable, "r1").WithArguments("r1").WithLocation(16, 16),
// (23,16): error CS8352: Cannot use variable 'r2' in this context because it may expose referenced variables outside of their declaration scope
// return r2;
Diagnostic(ErrorCode.ERR_EscapeVariable, "r2").WithArguments("r2").WithLocation(23, 16),
// (29,9): error CS8374: Cannot ref-assign 't' to 'F' because 't' has a narrower escape scope than 'F'.
// r3.F = ref t;
Diagnostic(ErrorCode.ERR_RefAssignNarrower, "r3.F = ref t").WithArguments("F", "t").WithLocation(29, 9),
// (39,16): error CS8352: Cannot use variable 'r4' in this context because it may expose referenced variables outside of their declaration scope
// return r4;
Diagnostic(ErrorCode.ERR_EscapeVariable, "r4").WithArguments("r4").WithLocation(39, 16),
// (46,16): error CS8352: Cannot use variable 'r5' in this context because it may expose referenced variables outside of their declaration scope
// return r5;
Diagnostic(ErrorCode.ERR_EscapeVariable, "r5").WithArguments("r5").WithLocation(46, 16),
// (53,16): error CS8352: Cannot use variable 'r6' in this context because it may expose referenced variables outside of their declaration scope
// return r6;
Diagnostic(ErrorCode.ERR_EscapeVariable, "r6").WithArguments("r6").WithLocation(53, 16),
// (59,9): error CS8374: Cannot ref-assign 't' to 'F' because 't' has a narrower escape scope than 'F'.
// r7.F = ref t;
Diagnostic(ErrorCode.ERR_RefAssignNarrower, "r7.F = ref t").WithArguments("F", "t").WithLocation(59, 9),
// (69,16): error CS8352: Cannot use variable 'r8' in this context because it may expose referenced variables outside of their declaration scope
// return r8;
Diagnostic(ErrorCode.ERR_EscapeVariable, "r8").WithArguments("r8").WithLocation(69, 16));
}
[Fact]
public void RefStructLocal_FromParameter_02()
{
var source =
@"ref struct R<T>
{
public ref T F;
public R(ref T t) { F = ref t; }
}
class Program
{
static R<T> Create<T>() => new R<T>();
static R<T> Create<T>(ref T t) => new R<T>(ref t);
static void F<T>(R<T> r) { }
static R<T> F1<T>(T t)
{
R<T> r1 = new R<T>(ref t);
F(r1);
return r1;
}
static R<T> F2<T>(T t)
{
scoped R<T> r2 = new R<T>(ref t);
F(r2);
return r2;
}
static R<T> F3<T>(T t)
{
R<T> r3 = new R<T>();
r3.F = ref t;
F(r3);
return r3;
}
static R<T> F4<T>(T t)
{
scoped R<T> r4 = new R<T>();
r4.F = ref t;
F(r4);
return r4;
}
static R<T> F5<T>(T t)
{
R<T> r5 = Create(ref t);
F(r5);
return r5;
}
static R<T> F6<T>(T t)
{
scoped R<T> r6 = Create(ref t);
F(r6);
return r6;
}
static R<T> F7<T>(T t)
{
R<T> r7 = Create<T>();
r7.F = ref t;
F(r7);
return r7;
}
static R<T> F8<T>(T t)
{
scoped R<T> r8 = Create<T>();
r8.F = ref t;
F(r8);
return r8;
}
}";
var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70);
comp.VerifyEmitDiagnostics(
// (15,16): error CS8352: Cannot use variable 'r1' in this context because it may expose referenced variables outside of their declaration scope
// return r1;
Diagnostic(ErrorCode.ERR_EscapeVariable, "r1").WithArguments("r1").WithLocation(15, 16),
// (21,16): error CS8352: Cannot use variable 'r2' in this context because it may expose referenced variables outside of their declaration scope
// return r2;
Diagnostic(ErrorCode.ERR_EscapeVariable, "r2").WithArguments("r2").WithLocation(21, 16),
// (26,9): error CS8374: Cannot ref-assign 't' to 'F' because 't' has a narrower escape scope than 'F'.
// r3.F = ref t;
Diagnostic(ErrorCode.ERR_RefAssignNarrower, "r3.F = ref t").WithArguments("F", "t").WithLocation(26, 9),
// (35,16): error CS8352: Cannot use variable 'r4' in this context because it may expose referenced variables outside of their declaration scope
// return r4;
Diagnostic(ErrorCode.ERR_EscapeVariable, "r4").WithArguments("r4").WithLocation(35, 16),
// (41,16): error CS8352: Cannot use variable 'r5' in this context because it may expose referenced variables outside of their declaration scope
// return r5;
Diagnostic(ErrorCode.ERR_EscapeVariable, "r5").WithArguments("r5").WithLocation(41, 16),
// (47,16): error CS8352: Cannot use variable 'r6' in this context because it may expose referenced variables outside of their declaration scope
// return r6;
Diagnostic(ErrorCode.ERR_EscapeVariable, "r6").WithArguments("r6").WithLocation(47, 16),
// (52,9): error CS8374: Cannot ref-assign 't' to 'F' because 't' has a narrower escape scope than 'F'.
// r7.F = ref t;
Diagnostic(ErrorCode.ERR_RefAssignNarrower, "r7.F = ref t").WithArguments("F", "t").WithLocation(52, 9),
// (61,16): error CS8352: Cannot use variable 'r8' in this context because it may expose referenced variables outside of their declaration scope
// return r8;
Diagnostic(ErrorCode.ERR_EscapeVariable, "r8").WithArguments("r8").WithLocation(61, 16));
}
[Fact]
public void LocalFromRvalueInvocation()
{
var source =
@"ref struct R<T> { }
class Program
{
static R<T> Create<T>(scoped ref T t)
{
return default;
}
static R<T> CreateReadonly<T>(scoped in T t)
{
return default;
}
static void F0(string s0)
{
R<string> r0;
r0 = Create(ref s0);
}
static void F1(ref string s1)
{
R<string> r1;
r1 = Create(ref s1);
}
static void F2(out string s2)
{
s2 = null;
R<string> r2;
r2 = Create(ref s2);
}
static void F3(in string s3)
{
R<string> r3;
r3 = CreateReadonly(in s3);
}
static void F4(scoped ref string s4)
{
R<string> r4;
r4 = Create(ref s4);
}
static void F5(scoped out string s5)
{
s5 = null;
R<string> r5;
r5 = Create(ref s5);
}
static void F6(scoped in string s6)
{
R<string> r6;
r6 = CreateReadonly(in s6);
}
}";
var comp = CreateCompilation(source);
comp.VerifyDiagnostics();
}
[Fact]
public void This_FromLocal()
{
var source =
@"ref struct R<T>
{
static R<T> Create() => new R<T>();
static R<T> Create(ref T t) => new R<T>(ref t);
static void M(R<T> r) { }
private ref T F;
public R(ref T t) { F = ref t; }
public R(sbyte unused)
{
T t1 = default;
this = new R<T>(ref t1);
M(this);
}
public R(short unused)
{
T t2 = default;
this = new R<T>();
this.F = ref t2;
M(this);
}
public R(int unused)
{
T t3 = default;
this = Create(ref t3);
M(this);
}
public R(long unused)
{
T t4 = default;
this = Create();
this.F = ref t4;
M(this);
}
}";
var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70);
comp.VerifyEmitDiagnostics(
// (11,16): error CS8347: Cannot use a result of 'R<T>.R(ref T)' in this context because it may expose variables referenced by parameter 't' outside of their declaration scope
// this = new R<T>(ref t1);
Diagnostic(ErrorCode.ERR_EscapeCall, "new R<T>(ref t1)").WithArguments("R<T>.R(ref T)", "t").WithLocation(11, 16),
// (11,29): error CS8168: Cannot return local 't1' by reference because it is not a ref local
// this = new R<T>(ref t1);
Diagnostic(ErrorCode.ERR_RefReturnLocal, "t1").WithArguments("t1").WithLocation(11, 29),
// (18,9): error CS8374: Cannot ref-assign 't2' to 'F' because 't2' has a narrower escape scope than 'F'.
// this.F = ref t2;
Diagnostic(ErrorCode.ERR_RefAssignNarrower, "this.F = ref t2").WithArguments("F", "t2").WithLocation(18, 9),
// (24,16): error CS8347: Cannot use a result of 'R<T>.Create(ref T)' in this context because it may expose variables referenced by parameter 't' outside of their declaration scope
// this = Create(ref t3);
Diagnostic(ErrorCode.ERR_EscapeCall, "Create(ref t3)").WithArguments("R<T>.Create(ref T)", "t").WithLocation(24, 16),
// (24,27): error CS8168: Cannot return local 't3' by reference because it is not a ref local
// this = Create(ref t3);
Diagnostic(ErrorCode.ERR_RefReturnLocal, "t3").WithArguments("t3").WithLocation(24, 27),
// (31,9): error CS8374: Cannot ref-assign 't4' to 'F' because 't4' has a narrower escape scope than 'F'.
// this.F = ref t4;
Diagnostic(ErrorCode.ERR_RefAssignNarrower, "this.F = ref t4").WithArguments("F", "t4").WithLocation(31, 9));
}
[Fact]
public void This_FromParameter()
{
var source =
@"ref struct R<T>
{
static R<T> Create() => new R<T>();
static R<T> Create(ref T t) => new R<T>(ref t);
static void M(R<T> r) { }
private ref T F;
R(ref T t) { F = ref t; }
R(sbyte unused, T t1)
{
this = new R<T>(ref t1);
M(this);
}
R(short unused, T t2)
{
this = new R<T>();
this.F = ref t2;
M(this);
}
R(int unused, T t3)
{
this = Create(ref t3);
M(this);
}
R(long unused, T t4)
{
this = Create();
this.F = ref t4;
M(this);
}
}";
var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70);
comp.VerifyEmitDiagnostics(
// (10,16): error CS8347: Cannot use a result of 'R<T>.R(ref T)' in this context because it may expose variables referenced by parameter 't' outside of their declaration scope
// this = new R<T>(ref t1);
Diagnostic(ErrorCode.ERR_EscapeCall, "new R<T>(ref t1)").WithArguments("R<T>.R(ref T)", "t").WithLocation(10, 16),
// (10,29): error CS8166: Cannot return a parameter by reference 't1' because it is not a ref parameter
// this = new R<T>(ref t1);
Diagnostic(ErrorCode.ERR_RefReturnParameter, "t1").WithArguments("t1").WithLocation(10, 29),
// (16,9): error CS8374: Cannot ref-assign 't2' to 'F' because 't2' has a narrower escape scope than 'F'.
// this.F = ref t2;
Diagnostic(ErrorCode.ERR_RefAssignNarrower, "this.F = ref t2").WithArguments("F", "t2").WithLocation(16, 9),
// (21,16): error CS8347: Cannot use a result of 'R<T>.Create(ref T)' in this context because it may expose variables referenced by parameter 't' outside of their declaration scope
// this = Create(ref t3);
Diagnostic(ErrorCode.ERR_EscapeCall, "Create(ref t3)").WithArguments("R<T>.Create(ref T)", "t").WithLocation(21, 16),
// (21,27): error CS8166: Cannot return a parameter by reference 't3' because it is not a ref parameter
// this = Create(ref t3);
Diagnostic(ErrorCode.ERR_RefReturnParameter, "t3").WithArguments("t3").WithLocation(21, 27),
// (27,9): error CS8374: Cannot ref-assign 't4' to 'F' because 't4' has a narrower escape scope than 'F'.
// this.F = ref t4;
Diagnostic(ErrorCode.ERR_RefAssignNarrower, "this.F = ref t4").WithArguments("F", "t4").WithLocation(27, 9));
}
[Fact]
public void This_FromRefParameter()
{
var source =
@"ref struct R<T>
{
static void M(R<T> r) { }
private ref T F;
R(ref T t) { F = ref t; }
R(sbyte unused, ref T t1)
{
this = new R<T>(ref t1);
M(this);
}
R(short unused, scoped ref T t2)
{
this = new R<T>(ref t2);
M(this);
}
}";
var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70);
comp.VerifyEmitDiagnostics(
// (13,16): error CS8347: Cannot use a result of 'R<T>.R(ref T)' in this context because it may expose variables referenced by parameter 't' outside of their declaration scope
// this = new R<T>(ref t2);
Diagnostic(ErrorCode.ERR_EscapeCall, "new R<T>(ref t2)").WithArguments("R<T>.R(ref T)", "t").WithLocation(13, 16),
// (13,29): error CS9075: Cannot return a parameter by reference 't2' because it is scoped to the current method
// this = new R<T>(ref t2);
Diagnostic(ErrorCode.ERR_RefReturnScopedParameter, "t2").WithArguments("t2").WithLocation(13, 29));
}
[Fact]
public void This_FromRefStructParameter()
{
var source =
@"ref struct R<T>
{
static void M(R<T> r) { }
private ref T F;
R(sbyte unused, ref R<T> r1)
{
this = r1;
M(this);
}
R(short unused, scoped ref R<T> r2)
{
this = r2;
M(this);
}
}";
var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70);
comp.VerifyEmitDiagnostics(
// (4,19): warning CS0169: The field 'R<T>.F' is never used
// private ref T F;
Diagnostic(ErrorCode.WRN_UnreferencedField, "F").WithArguments("R<T>.F").WithLocation(4, 19));
}
[WorkItem(63140, "https://github.com/dotnet/roslyn/issues/63140")]
[Fact]
public void Scoped_Cycle()
{
var source =
@"interface I
{
void M<T>(T s);
}
class C : I
{
void I.M<T>(scoped T? s) {}
}";
var comp = CreateCompilation(source);
comp.VerifyDiagnostics(
// (6,11): error CS0535: 'C' does not implement interface member 'I.M<T>(T)'
// class C : I
Diagnostic(ErrorCode.ERR_UnimplementedInterfaceMember, "I").WithArguments("C", "I.M<T>(T)").WithLocation(6, 11),
// (8,12): error CS0539: 'C.M<T>(scoped T?)' in explicit interface declaration is not found among members of the interface that can be implemented
// void I.M<T>(scoped T? s) {}
Diagnostic(ErrorCode.ERR_InterfaceMemberNotFound, "M").WithArguments("C.M<T>(scoped T?)").WithLocation(8, 12),
// (8,17): error CS9048: The 'scoped' modifier can be used for refs and ref struct values only.
// void I.M<T>(scoped T? s) {}
Diagnostic(ErrorCode.ERR_ScopedRefAndRefStructOnly, "scoped T? s").WithLocation(8, 17),
// (8,25): warning CS8632: The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.
// void I.M<T>(scoped T? s) {}
Diagnostic(ErrorCode.WRN_MissingNonNullTypesContextForAnnotation, "?").WithLocation(8, 25),
// (8,27): error CS0453: The type 'T' must be a non-nullable value type in order to use it as parameter 'T' in the generic type or method 'Nullable<T>'
// void I.M<T>(scoped T? s) {}
Diagnostic(ErrorCode.ERR_ValConstraintNotSatisfied, "s").WithArguments("System.Nullable<T>", "T", "T").WithLocation(8, 27));
}
[Fact]
public void NestedScope()
{
var source =
@"ref struct R<T>
{
public ref T F;
}
class Program
{
static T F<T>()
{
scoped R<T> r;
{
T t = default;
r.F = ref t;
}
return r.F;
}
}";
var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70);
comp.VerifyEmitDiagnostics(
// (12,13): error CS8374: Cannot ref-assign 't' to 'F' because 't' has a narrower escape scope than 'F'.
// r.F = ref t;
Diagnostic(ErrorCode.ERR_RefAssignNarrower, "r.F = ref t").WithArguments("F", "t").WithLocation(12, 13));
}
[Theory]
[InlineData(LanguageVersion.CSharp10)]
[InlineData(LanguageVersion.CSharp11)]
public void InstanceMethodWithOutVar_01(LanguageVersion languageVersion)
{
var source =
@"using System;
ref struct R
{
public R(Span<int> s) { }
public void F(out R r) { r = default; }
}
class Program
{
static void F(out R r)
{
Span<int> s1 = stackalloc int[10];
R r1 = new R(s1);
r1.F(out r);
}
}";
var comp = CreateCompilationWithSpanAndMemoryExtensions(source, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion));
comp.VerifyDiagnostics(
// (13,9): error CS8352: Cannot use variable 'r1' in this context because it may expose referenced variables outside of their declaration scope
// r1.F(out r);
Diagnostic(ErrorCode.ERR_EscapeVariable, "r1").WithArguments("r1").WithLocation(13, 9),
// (13,9): error CS8350: This combination of arguments to 'R.F(out R)' is disallowed because it may expose variables referenced by parameter 'this' outside of their declaration scope
// r1.F(out r);
Diagnostic(ErrorCode.ERR_CallArgMixing, "r1.F(out r)").WithArguments("R.F(out R)", "this").WithLocation(13, 9));
}
[Fact]
public void InstanceMethodWithOutVar_02()
{
var source =
@"ref struct R
{
public ref int _i;
public R(ref int i) { _i = ref i; }
public void F(out R r) { r = new R(ref _i); }
}
class Program
{
static void F(out R r)
{
int i = 0;
R r1 = new R(ref i);
r1.F(out r);
}
}";
var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70);
comp.VerifyDiagnostics(
// (13,9): error CS8352: Cannot use variable 'r1' in this context because it may expose referenced variables outside of their declaration scope
// r1.F(out r);
Diagnostic(ErrorCode.ERR_EscapeVariable, "r1").WithArguments("r1").WithLocation(13, 9),
// (13,9): error CS8350: This combination of arguments to 'R.F(out R)' is disallowed because it may expose variables referenced by parameter 'this' outside of their declaration scope
// r1.F(out r);
Diagnostic(ErrorCode.ERR_CallArgMixing, "r1.F(out r)").WithArguments("R.F(out R)", "this").WithLocation(13, 9));
}
[Theory]
[InlineData(LanguageVersion.CSharp10)]
[InlineData(LanguageVersion.CSharp11)]
public void InstanceMethodWithOutVar_03(LanguageVersion languageVersion)
{
var source =
@"using System;
ref struct R
{
public void F(out Span<int> s) { s = default; }
}
class Program
{
static void Main()
{
Span<int> s = stackalloc int[10];
R r = new R();
r.F(out s);
}
}";
var comp = CreateCompilationWithSpanAndMemoryExtensions(source, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion), targetFramework: TargetFramework.Net50);
if (languageVersion == LanguageVersion.CSharp10)
{
comp.VerifyDiagnostics(
// (12,9): error CS8350: This combination of arguments to 'R.F(out Span<int>)' is disallowed because it may expose variables referenced by parameter 's' outside of their declaration scope
// r.F(out s);
Diagnostic(ErrorCode.ERR_CallArgMixing, "r.F(out s)").WithArguments("R.F(out System.Span<int>)", "s").WithLocation(12, 9),
// (12,17): error CS8352: Cannot use variable 's' in this context because it may expose referenced variables outside of their declaration scope
// r.F(out s);
Diagnostic(ErrorCode.ERR_EscapeVariable, "s").WithArguments("s").WithLocation(12, 17));
}
else
{
comp.VerifyDiagnostics();
}
}
[WorkItem(63016, "https://github.com/dotnet/roslyn/issues/63016")]
[Fact]
public void RefToLocalFromInstanceMethod_01()
{
var source =
@"ref struct R
{
private ref int _i;
public void M1()
{
int i = 42;
M2(ref i);
}
private void M2(ref int i)
{
_i = ref i;
}
}";
var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70);
comp.VerifyDiagnostics(
// (11,9): error CS9079: Cannot ref-assign 'i' to '_i' because 'i' can only escape the current method through a return statement.
// _i = ref i;
Diagnostic(ErrorCode.ERR_RefAssignReturnOnly, "_i = ref i").WithArguments("_i", "i").WithLocation(11, 9));
}
[WorkItem(63016, "https://github.com/dotnet/roslyn/issues/63016")]
[Fact]
public void RefToLocalFromInstanceMethod_02()
{
var sourceB =
@"using System;
ref struct S
{
private ref int _i;
public S(ref int i)
{
Span<int> s = stackalloc int[100];
M2(ref s[0]);
}
private void M2(ref int i)
{
_i = ref i;
}
}";
var comp = CreateCompilation(sourceB, options: TestOptions.UnsafeReleaseDll, targetFramework: TargetFramework.Net70);
comp.VerifyDiagnostics(
// (12,9): error CS9079: Cannot ref-assign 'i' to '_i' because 'i' can only escape the current method through a return statement.
// _i = ref i;
Diagnostic(ErrorCode.ERR_RefAssignReturnOnly, "_i = ref i").WithArguments("_i", "i").WithLocation(12, 9));
}
[Fact]
public void RefStructProperty_01()
{
var source =
@"ref struct R<T>
{
public R(ref T t) { }
}
class C
{
R<object> this[R<int> r] => default;
static R<object> F1(C c)
{
int i = 1;
var r1 = new R<int>(ref i);
return c[r1]; // 1
}
static R<object> F2(C c)
{
var r2 = new R<int>();
return c[r2];
}
}";
var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10);
comp.VerifyDiagnostics();
comp = CreateCompilation(source);
comp.VerifyDiagnostics(
// (12,16): error CS8347: Cannot use a result of 'C.this[R<int>]' in this context because it may expose variables referenced by parameter 'r' outside of their declaration scope
// return c[r1]; // 1
Diagnostic(ErrorCode.ERR_EscapeCall, "c[r1]").WithArguments("C.this[R<int>]", "r").WithLocation(12, 16),
// (12,18): error CS8352: Cannot use variable 'r1' in this context because it may expose referenced variables outside of their declaration scope
// return c[r1]; // 1
Diagnostic(ErrorCode.ERR_EscapeVariable, "r1").WithArguments("r1").WithLocation(12, 18));
}
[Fact]
public void RefStructProperty_02()
{
var source =
@"ref struct R<T>
{
}
class C
{
R<object> this[in int i] => default;
static R<object> F1(C c)
{
int i1 = 1;
return c[i1]; // 1
}
static R<object> F2(C c)
{
return c[2]; // 2
}
static R<object> F2(C c, in int i3)
{
return c[i3];
}
}";
var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10);
comp.VerifyDiagnostics();
comp = CreateCompilation(source);
comp.VerifyDiagnostics(
// (10,16): error CS8347: Cannot use a result of 'C.this[in int]' in this context because it may expose variables referenced by parameter 'i' outside of their declaration scope
// return c[i1]; // 1
Diagnostic(ErrorCode.ERR_EscapeCall, "c[i1]").WithArguments("C.this[in int]", "i").WithLocation(10, 16),
// (10,18): error CS8168: Cannot return local 'i1' by reference because it is not a ref local
// return c[i1]; // 1
Diagnostic(ErrorCode.ERR_RefReturnLocal, "i1").WithArguments("i1").WithLocation(10, 18),
// (14,16): error CS8347: Cannot use a result of 'C.this[in int]' in this context because it may expose variables referenced by parameter 'i' outside of their declaration scope
// return c[2]; // 2
Diagnostic(ErrorCode.ERR_EscapeCall, "c[2]").WithArguments("C.this[in int]", "i").WithLocation(14, 16),
// (14,18): error CS8156: An expression cannot be used in this context because it may not be passed or returned by reference
// return c[2]; // 2
Diagnostic(ErrorCode.ERR_RefReturnLvalueExpected, "2").WithLocation(14, 18));
}
[Theory]
[InlineData(LanguageVersion.CSharp10)]
[InlineData(LanguageVersion.CSharp11)]
public void ReturnThis_01(LanguageVersion languageVersion)
{
var source =
@"ref struct R
{
R F1() => this;
ref R F2() => ref this;
ref readonly R F3() => ref this;
}";
var comp = CreateCompilation(source, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion));
comp.VerifyDiagnostics(
// (4,23): error CS8170: Struct members cannot return 'this' or other instance members by reference
// ref R F2() => ref this;
Diagnostic(ErrorCode.ERR_RefReturnStructThis, "this").WithLocation(4, 23),
// (5,32): error CS8170: Struct members cannot return 'this' or other instance members by reference
// ref readonly R F3() => ref this;
Diagnostic(ErrorCode.ERR_RefReturnStructThis, "this").WithLocation(5, 32));
}
[Theory]
[InlineData(LanguageVersion.CSharp10)]
[InlineData(LanguageVersion.CSharp11)]
public void ReturnThis_02(LanguageVersion languageVersion)
{
var source =
@"readonly ref struct R
{
R F1() => this;
ref R F2() => ref this;
ref readonly R F3() => ref this;
}";
var comp = CreateCompilation(source, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion));
comp.VerifyDiagnostics(
// (4,23): error CS8354: Cannot return 'this' by reference.
// ref R F2() => ref this;
Diagnostic(ErrorCode.ERR_RefReturnThis, "this").WithLocation(4, 23),
// (5,32): error CS8170: Struct members cannot return 'this' or other instance members by reference
// ref readonly R F3() => ref this;
Diagnostic(ErrorCode.ERR_RefReturnStructThis, "this").WithLocation(5, 32));
}
[Fact, WorkItem(63526, "https://github.com/dotnet/roslyn/issues/63526")]
public void ReturnThis_03()
{
var source = """
using System.Diagnostics.CodeAnalysis;
ref struct S2 {
public S S;
}
ref struct S {
public int field;
public ref int refField;
ref int Prop1 => ref field; // 1
[UnscopedRef]
ref int Prop2 => ref field; // okay
S2 Prop3 => new S2 { S = this }; // Okay
S Prop4 => new S { refField = ref this.field }; // 2
[UnscopedRef]
S Prop5 => new S { refField = ref this.field }; // okay
S M1() => new S { refField = ref this.field }; // 3
[UnscopedRef]
S M2() => new S { refField = ref this.field }; // okay
static S M3(scoped ref S s) => new S { refField = ref s.field }; // 4
static S M4(ref S s) => new S { refField = ref s.field }; // okay
}
""";
var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70);
comp.VerifyDiagnostics(
// (11,26): error CS8170: Struct members cannot return 'this' or other instance members by reference
// ref int Prop1 => ref field; // 1
Diagnostic(ErrorCode.ERR_RefReturnStructThis, "field").WithLocation(11, 26),
// (18,24): error CS8170: Struct members cannot return 'this' or other instance members by reference
// S Prop4 => new S { refField = ref this.field }; // 2
Diagnostic(ErrorCode.ERR_RefReturnStructThis, "refField = ref this.field").WithLocation(18, 24),
// (23,23): error CS8170: Struct members cannot return 'this' or other instance members by reference
// S M1() => new S { refField = ref this.field }; // 3
Diagnostic(ErrorCode.ERR_RefReturnStructThis, "refField = ref this.field").WithLocation(23, 23),
// (28,59): error CS9076: Cannot return by reference a member of parameter 's' because it is scoped to the current method
// static S M3(scoped ref S s) => new S { refField = ref s.field }; // 4
Diagnostic(ErrorCode.ERR_RefReturnScopedParameter2, "s").WithArguments("s").WithLocation(28, 59));
}
[Fact]
public void RefInitializer_LangVer()
{
var source = @"
int x = 42;
var r = new R() { field = ref x };
ref struct R
{
public ref int field;
}
";
var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10, targetFramework: TargetFramework.Net70);
comp.VerifyDiagnostics(
// (7,12): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater.
// public ref int field;
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "ref int").WithArguments("ref fields", "11.0").WithLocation(7, 12)
);
comp = CreateCompilation(source, parseOptions: TestOptions.Regular11, targetFramework: TargetFramework.Net70);
comp.VerifyDiagnostics();
}
[Fact]
public void RefInitializer_LangVer_FromMetadata()
{
var lib_cs = @"
public ref struct R
{
public ref int field;
}
";
var source = @"
int x = 42;
var r1 = new R() { field = ref x }; // 1
var r2 = new R() { field = x }; // 2
R r3 = default;
_ = r3 with { field = ref x }; // 3
";
var lib = CreateCompilation(lib_cs, parseOptions: TestOptions.Regular11, targetFramework: TargetFramework.Net70);
var comp = CreateCompilation(source, references: new[] { lib.EmitToImageReference() }, parseOptions: TestOptions.Regular10, targetFramework: TargetFramework.Net70);
comp.VerifyDiagnostics(
// (3,20): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater.
// var r1 = new R() { field = ref x }; // 1
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "field").WithArguments("ref fields", "11.0").WithLocation(3, 20),
// (4,20): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater.
// var r2 = new R() { field = x }; // 2
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "field").WithArguments("ref fields", "11.0").WithLocation(4, 20),
// (7,15): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater.
// _ = r3 with { field = ref x }; // 3
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "field").WithArguments("ref fields", "11.0").WithLocation(7, 15)
);
comp = CreateCompilation(source, references: new[] { lib.EmitToImageReference() }, parseOptions: TestOptions.Regular10);
comp.VerifyDiagnostics(
// (3,20): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater.
// var r1 = new R() { field = ref x }; // 1
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "field").WithArguments("ref fields", "11.0").WithLocation(3, 20),
// (3,20): error CS9064: Target runtime doesn't support ref fields.
// var r1 = new R() { field = ref x }; // 1
Diagnostic(ErrorCode.ERR_RuntimeDoesNotSupportRefFields, "field").WithLocation(3, 20),
// (4,20): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater.
// var r2 = new R() { field = x }; // 2
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "field").WithArguments("ref fields", "11.0").WithLocation(4, 20),
// (4,20): error CS9064: Target runtime doesn't support ref fields.
// var r2 = new R() { field = x }; // 2
Diagnostic(ErrorCode.ERR_RuntimeDoesNotSupportRefFields, "field").WithLocation(4, 20),
// (7,15): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater.
// _ = r3 with { field = ref x }; // 3
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "field").WithArguments("ref fields", "11.0").WithLocation(7, 15),
// (7,15): error CS9064: Target runtime doesn't support ref fields.
// _ = r3 with { field = ref x }; // 3
Diagnostic(ErrorCode.ERR_RuntimeDoesNotSupportRefFields, "field").WithLocation(7, 15)
);
}
[Fact]
public void RefInitializer()
{
var source = @"
public class C
{
public static void Main()
{
int x = 42;
var r = new R() { field = ref x };
System.Console.Write(r.ToString());
}
}
ref struct R
{
public ref int field;
public override string ToString()
{
return field.ToString();
}
}
";
var comp = CreateCompilation(source, options: TestOptions.ReleaseExe, targetFramework: TargetFramework.Net70);
comp.VerifyDiagnostics();
var verifier = CompileAndVerify(comp, verify: Verification.Skipped, expectedOutput: IncludeExpectedOutput("42"));
verifier.VerifyIL("C.Main",
"""
{
// Code size 41 (0x29)
.maxstack 2
.locals init (int V_0, //x
R V_1, //r
R V_2)
IL_0000: ldc.i4.s 42
IL_0002: stloc.0
IL_0003: ldloca.s V_2
IL_0005: initobj "R"
IL_000b: ldloca.s V_2
IL_000d: ldloca.s V_0
IL_000f: stfld "ref int R.field"
IL_0014: ldloc.2
IL_0015: stloc.1
IL_0016: ldloca.s V_1
IL_0018: constrained. "R"
IL_001e: callvirt "string object.ToString()"
IL_0023: call "void System.Console.Write(string)"
IL_0028: ret
}
""");
}
[Fact]
public void RefInitializer_RHSMustBeDefinitelyAssigned()
{
// The right operand must be definitely assigned at the point of the ref assignment.
var source = @"
int x;
var r = new R() { field = ref x };
ref struct R
{
public ref int field;
public override string ToString()
{
return field.ToString();
}
}
";
var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70);
comp.VerifyDiagnostics(
// (3,31): error CS0165: Use of unassigned local variable 'x'
// var r = new R() { field = ref x };
Diagnostic(ErrorCode.ERR_UseDefViolation, "x").WithArguments("x").WithLocation(3, 31)
);
}
[Fact]
public void RefInitializer_RHSTypeMustMatch()
{
// The right operand must be an expression that yields an lvalue designating a value of the same type as the left operand.
var source = @"
object x = null;
var r = new R() { field = ref x };
ref struct R
{
public ref int field;
public override string ToString()
{
return field.ToString();
}
}
";
var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70);
comp.VerifyDiagnostics(
// (3,31): error CS8173: The expression must be of type 'int' because it is being assigned by reference
// var r = new R() { field = ref x };
Diagnostic(ErrorCode.ERR_RefAssignmentMustHaveIdentityConversion, "x").WithArguments("int").WithLocation(3, 31)
);
}
[Fact]
public void RefInitializer_RHSTypeMustMatch_ImplicitConversionExists()
{
// The right operand must be an expression that yields an lvalue designating a value of the same type as the left operand.
var source = @"
S1 x = default;
var r = new R() { field = ref x };
struct S1 { }
struct S2
{
public static implicit operator S2(S1 s1) => throw null;
}
ref struct R
{
public ref S2 field;
public override string ToString()
{
return field.ToString();
}
}
";
var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70);
comp.VerifyDiagnostics(
// (3,31): error CS8173: The expression must be of type 'S2' because it is being assigned by reference
// var r = new R() { field = ref x };
Diagnostic(ErrorCode.ERR_RefAssignmentMustHaveIdentityConversion, "x").WithArguments("S2").WithLocation(3, 31)
);
}
[Fact]
public void RefInitializer_StaticRefField()
{
var source = @"
int x = 0;
var r = new R() { field = ref x };
ref struct R
{
public static ref int field;
public override string ToString()
{
return field.ToString();
}
}
";
var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70);
comp.VerifyDiagnostics(
// (3,19): error CS1914: Static field or property 'R.field' cannot be assigned in an object initializer
// var r = new R() { field = ref x };
Diagnostic(ErrorCode.ERR_StaticMemberInObjectInitializer, "field").WithArguments("R.field").WithLocation(3, 19),
// (7,27): error CS0106: The modifier 'static' is not valid for this item
// public static ref int field;
Diagnostic(ErrorCode.ERR_BadMemberFlag, "field").WithArguments("static").WithLocation(7, 27)
);
}
[Fact]
public void RefInitializer_VarInvocationReserved()
{
var source = @"
var r = new R() { field = ref var() };
ref struct R
{
public ref int field;
}
";
var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70);
comp.VerifyDiagnostics(
// (2,31): error CS8199: The syntax 'var (...)' as an lvalue is reserved.
// var r = new R() { field = ref var() };
Diagnostic(ErrorCode.ERR_VarInvocationLvalueReserved, "var()").WithLocation(2, 31),
// (2,31): error CS0103: The name 'var' does not exist in the current context
// var r = new R() { field = ref var() };
Diagnostic(ErrorCode.ERR_NameNotInContext, "var").WithArguments("var").WithLocation(2, 31)
);
}
[Fact]
public void RefInitializer_ReadonlyRefField()
{
var source = @"
int x = 42;
var r = new R() { field = ref x };
ref struct R
{
public readonly ref int field;
}
";
var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70);
comp.VerifyDiagnostics(
// (3,19): 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)
// var r = new R() { field = ref x };
Diagnostic(ErrorCode.ERR_AssgReadonly, "field").WithLocation(3, 19)
);
}
[Fact]
public void RefInitializer_RefReadonlyField()
{
var source = @"
int x = 42;
var r = new R() { field = ref x };
ref struct R
{
public ref readonly int field;
}
";
var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70);
comp.VerifyDiagnostics();
}
[Fact]
public void RefInitializer_RefReadonlyValue_Field()
{
// If the left operand is a writeable ref (i.e. it designates anything other than a `ref readonly` local or `in` parameter), then the right operand must be a writeable lvalue.
var source = @"
class C
{
ref readonly int Value() => throw null;
void M()
{
var r = new R() { field = ref Value() };
}
}
ref struct R
{
public ref int field;
}
";
var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70);
comp.VerifyDiagnostics(
// (8,39): error CS8331: Cannot assign to method 'Value' or use it as the right hand side of a ref assignment because it is a readonly variable
// var r = new R() { field = ref Value() };
Diagnostic(ErrorCode.ERR_AssignReadonlyNotField, "Value()").WithArguments("method", "Value").WithLocation(8, 39)
);
}
[Fact]
public void RefInitializer_AssignInParameter()
{
var source = @"
class C
{
static void F(in int i)
{
_ = new R1 { _f = ref i };
_ = new R2 { _f = ref i }; // 1
}
}
ref struct R1
{
public ref readonly int _f;
}
ref struct R2
{
public ref int _f;
}
";
var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70);
comp.VerifyDiagnostics(
// (7,31): error CS8331: Cannot assign to variable 'i' or use it as the right hand side of a ref assignment because it is a readonly variable
// _ = new R2 { _f = ref i }; // 1
Diagnostic(ErrorCode.ERR_AssignReadonlyNotField, "i").WithArguments("variable", "i").WithLocation(7, 31)
);
}
[Fact]
public void RefInitializer_RefReadonlyValue_GetOnlyProperty()
{
var source = @"
class C
{
ref readonly int Value() => throw null;
void M()
{
var r = new R() { Property = ref Value() };
}
}
ref struct R
{
public ref int Property { get => throw null; }
}
";
var comp = CreateCompilation(source);
comp.VerifyDiagnostics(
// (8,27): error CS8373: The left-hand side of a ref assignment must be a ref variable.
// var r = new R() { Property = ref Value() };
Diagnostic(ErrorCode.ERR_RefLocalOrParamExpected, "Property").WithLocation(8, 27)
);
}
[Fact]
public void RefInitializer_RefReadonlyValue_Property()
{
var source = @"
class C
{
ref readonly int Value() => throw null;
void M()
{
var r = new R() { Property = ref Value() };
}
}
ref struct R
{
public ref int Property { get => throw null; set => throw null; }
}
";
var comp = CreateCompilation(source);
comp.VerifyDiagnostics(
// (8,27): error CS8373: The left-hand side of a ref assignment must be a ref variable.
// var r = new R() { Property = ref Value() };
Diagnostic(ErrorCode.ERR_RefLocalOrParamExpected, "Property").WithLocation(8, 27),
// (14,50): error CS8147: Properties which return by reference cannot have set accessors
// public ref int Property { get => throw null; set => throw null; }
Diagnostic(ErrorCode.ERR_RefPropertyCannotHaveSetAccessor, "set").WithLocation(14, 50)
);
}
[Fact]
public void RefInitializer_RefReadonlyValue_Indexer()
{
var source = @"
var r = new R() { [0] = ref Value() }; // 1
R r2 = default;
r2[0] = ref Value(); // 2
ref readonly int Value() => throw null;
ref struct R
{
public ref int this[int i] { get => throw null; }
}
";
var comp = CreateCompilation(source);
comp.VerifyDiagnostics(
// (2,19): error CS8373: The left-hand side of a ref assignment must be a ref variable.
// var r = new R() { [0] = ref Value() }; // 1
Diagnostic(ErrorCode.ERR_RefLocalOrParamExpected, "[0]").WithLocation(2, 19),
// (5,1): error CS8373: The left-hand side of a ref assignment must be a ref variable.
// r2[0] = ref Value(); // 2
Diagnostic(ErrorCode.ERR_RefLocalOrParamExpected, "r2[0]").WithLocation(5, 1)
);
}
[Fact]
public void RefInitializer_Indexer()
{
var source = @"
var r = new R() { [0] = ref Value() }; // 1
R r2 = default;
r2[0] = ref Value(); // 2
ref int Value() => throw null;
ref struct R
{
public ref int this[int i] { get => throw null; }
}
";
var comp = CreateCompilation(source);
comp.VerifyDiagnostics(
// (2,19): error CS8373: The left-hand side of a ref assignment must be a ref variable.
// var r = new R() { [0] = ref Value() }; // 1
Diagnostic(ErrorCode.ERR_RefLocalOrParamExpected, "[0]").WithLocation(2, 19),
// (5,1): error CS8373: The left-hand side of a ref assignment must be a ref variable.
// r2[0] = ref Value(); // 2
Diagnostic(ErrorCode.ERR_RefLocalOrParamExpected, "r2[0]").WithLocation(5, 1)
);
}
[Fact]
public void RefInitializer_ValueMustReferToLocation()
{
var source = @"
class C
{
int Value() => throw null;
void M()
{
var r = new R() { field = ref Value() };
}
}
ref struct R
{
public ref int field;
}
";
var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70);
comp.VerifyDiagnostics(
// (8,39): error CS1510: A ref or out value must be an assignable variable
// var r = new R() { field = ref Value() };
Diagnostic(ErrorCode.ERR_RefLvalueExpected, "Value()").WithLocation(8, 39)
);
}
[Fact]
public void RefInitializer_RefReadonlyField_RefReadonlyValue()
{
var source = @"
class C
{
ref readonly int Value() => throw null;
void M()
{
var r = new R() { field = ref Value() };
}
}
ref struct R
{
public ref readonly int field;
}
";
var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70);
comp.VerifyDiagnostics();
}
[Fact]
public void RefInitializer_OnInterface_Field()
{
var source = @"
class C
{
void M<T>() where T : I, new()
{
int x = 42;
var t = new T() { field = ref x };
}
}
interface I
{
public ref int field;
}
";
var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70);
comp.VerifyDiagnostics(
// (12,20): error CS0525: Interfaces cannot contain instance fields
// public ref int field;
Diagnostic(ErrorCode.ERR_InterfacesCantContainFields, "field").WithLocation(12, 20),
// (12,20): error CS9059: A ref field can only be declared in a ref struct.
// public ref int field;
Diagnostic(ErrorCode.ERR_RefFieldInNonRefStruct, "field").WithLocation(12, 20)
);
}
[Fact]
public void RefInitializer_OnInterface_Property()
{
var source = @"
class C
{
void M<T>() where T : I, new()
{
int x = 42;
var t = new T() { Property = ref x };
}
}
interface I
{
public ref int Property { get; }
}
";
var comp = CreateCompilation(source);
comp.VerifyDiagnostics(
// (7,27): error CS8373: The left-hand side of a ref assignment must be a ref variable.
// var t = new T() { Property = ref x };
Diagnostic(ErrorCode.ERR_RefLocalOrParamExpected, "Property").WithLocation(7, 27)
);
}
[Fact]
public void RefInitializer_Collection()
{
var source = @"
using System.Collections;
int x = 42;
int y = 43;
var r = new R() { ref x, ref y };
struct R : IEnumerable
{
public void Add(ref int x) => throw null;
public IEnumerator GetEnumerator() => throw null;
}
";
var comp = CreateCompilation(source);
comp.VerifyDiagnostics(
// (4,5): warning CS0219: The variable 'x' is assigned but its value is never used
// int x = 42;
Diagnostic(ErrorCode.WRN_UnreferencedVarAssg, "x").WithArguments("x").WithLocation(4, 5),
// (5,5): warning CS0219: The variable 'y' is assigned but its value is never used
// int y = 43;
Diagnostic(ErrorCode.WRN_UnreferencedVarAssg, "y").WithArguments("y").WithLocation(5, 5),
// (6,19): error CS1073: Unexpected token 'ref'
// var r = new R() { ref x, ref y };
Diagnostic(ErrorCode.ERR_UnexpectedToken, "ref").WithArguments("ref").WithLocation(6, 19),
// (6,26): error CS1073: Unexpected token 'ref'
// var r = new R() { ref x, ref y };
Diagnostic(ErrorCode.ERR_UnexpectedToken, "ref").WithArguments("ref").WithLocation(6, 26)
);
}
[Fact]
public void RefInitializer_OnNonRefField()
{
var source = @"
int x = 42;
var r = new R() { field = ref x }; // 1
R r2 = default;
r2.field = ref x; // 2
ref struct R
{
public int field;
}
";
var comp = CreateCompilation(source);
comp.VerifyDiagnostics(
// (3,19): error CS8373: The left-hand side of a ref assignment must be a ref variable.
// var r = new R() { field = ref x }; // 1
Diagnostic(ErrorCode.ERR_RefLocalOrParamExpected, "field").WithLocation(3, 19),
// (6,1): error CS8373: The left-hand side of a ref assignment must be a ref variable.
// r2.field = ref x; // 2
Diagnostic(ErrorCode.ERR_RefLocalOrParamExpected, "r2.field").WithLocation(6, 1)
);
}
[Fact]
public void RefInitializer_OnNonRefProperty()
{
var source = @"
int x = 42;
var r = new R() { Property = ref x }; // 1
R r2 = default;
r2.Property = ref x; // 2
ref struct R
{
public int Property { get; set; }
}
";
var comp = CreateCompilation(source);
comp.VerifyDiagnostics(
// (3,19): error CS8373: The left-hand side of a ref assignment must be a ref variable.
// var r = new R() { Property = ref x }; // 1
Diagnostic(ErrorCode.ERR_RefLocalOrParamExpected, "Property").WithLocation(3, 19),
// (6,1): error CS8373: The left-hand side of a ref assignment must be a ref variable.
// r2.Property = ref x; // 2
Diagnostic(ErrorCode.ERR_RefLocalOrParamExpected, "r2.Property").WithLocation(6, 1)
);
}
[Fact]
public void RefInitializer_OnNonRefIndexer()
{
var source = @"
int x = 42;
var r = new R() { [0] = ref x }; // 1
R r2 = default;
r2[0] = ref x; // 2
ref struct R
{
public int this[int i] { get => throw null; set => throw null; }
}
";
var comp = CreateCompilation(source);
comp.VerifyDiagnostics(
// (3,19): error CS8373: The left-hand side of a ref assignment must be a ref variable.
// var r = new R() { [0] = ref x }; // 1
Diagnostic(ErrorCode.ERR_RefLocalOrParamExpected, "[0]").WithLocation(3, 19),
// (6,1): error CS8373: The left-hand side of a ref assignment must be a ref variable.
// r2[0] = ref x; // 2
Diagnostic(ErrorCode.ERR_RefLocalOrParamExpected, "r2[0]").WithLocation(6, 1)
);
}
[Fact]
public void RefInitializer_OnArray()
{
var source = @"
public ref struct C
{
C M()
{
int x = 0;
var c = new C { array = { [0] = ref x } }; // 1
return c;
}
void M2()
{
int x = 0;
C c2 = new C();
c2.array[0] = ref x; // 2
}
public int[] array;
}
";
var comp = CreateCompilation(source);
comp.VerifyDiagnostics(
// (7,35): error CS8373: The left-hand side of a ref assignment must be a ref variable.
// var c = new C { array = { [0] = ref x } }; // 1
Diagnostic(ErrorCode.ERR_RefLocalOrParamExpected, "[0]").WithLocation(7, 35),
// (15,9): error CS8373: The left-hand side of a ref assignment must be a ref variable.
// c2.array[0] = ref x; // 2
Diagnostic(ErrorCode.ERR_RefLocalOrParamExpected, "c2.array[0]").WithLocation(15, 9)
);
}
[Fact]
public void RefInitializer_OnPointer()
{
var source = @"
public unsafe class C
{
public int* pointer;
C M()
{
int x = 0;
var c = new C { pointer = { [0] = ref x } }; // 1
return c;
}
void M2()
{
int x = 0;
C c2 = new C();
c2.pointer[0] = ref x; // 2
}
}
";
var comp = CreateCompilation(source, options: TestOptions.UnsafeDebugDll);
comp.VerifyDiagnostics(
// (9,37): error CS8373: The left-hand side of a ref assignment must be a ref variable.
// var c = new C { pointer = { [0] = ref x } }; // 1
Diagnostic(ErrorCode.ERR_RefLocalOrParamExpected, "[0]").WithLocation(9, 37),
// (17,9): error CS8373: The left-hand side of a ref assignment must be a ref variable.
// c2.pointer[0] = ref x; // 2
Diagnostic(ErrorCode.ERR_RefLocalOrParamExpected, "c2.pointer[0]").WithLocation(17, 9)
);
}
[Fact]
public void RefInitializer_OnEvent()
{
var source = @"
int x = 42;
var r = new C { a = ref x }; // 1
C c = default;
c.a = ref x; // 2
class C
{
public event System.Action a;
}
";
var comp = CreateCompilation(source);
comp.VerifyDiagnostics(
// (3,17): error CS0070: The event 'C.a' can only appear on the left hand side of += or -= (except when used from within the type 'C')
// var r = new C { a = ref x }; // 1
Diagnostic(ErrorCode.ERR_BadEventUsage, "a").WithArguments("C.a", "C").WithLocation(3, 17),
// (6,3): error CS0070: The event 'C.a' can only appear on the left hand side of += or -= (except when used from within the type 'C')
// c.a = ref x; // 2
Diagnostic(ErrorCode.ERR_BadEventUsage, "a").WithArguments("C.a", "C").WithLocation(6, 3)
);
}
[Fact]
public void RefInitializer_OnEvent_ThisMemberAccess()
{
var source = @"
int x = 42;
var r1 = new C { this.a = ref x }; // 1
class C
{
public event System.Action a;
}
";
var comp = CreateCompilation(source);
comp.VerifyDiagnostics(
// (3,16): error CS1922: Cannot initialize type 'C' with a collection initializer because it does not implement 'System.Collections.IEnumerable'
// var r1 = new C { this.a = ref x }; // 1
Diagnostic(ErrorCode.ERR_CollectionInitRequiresIEnumerable, "{ this.a = ref x }").WithArguments("C").WithLocation(3, 16),
// (3,18): error CS0747: Invalid initializer member declarator
// var r1 = new C { this.a = ref x }; // 1
Diagnostic(ErrorCode.ERR_InvalidInitializerElementInitializer, "this.a = ref x").WithLocation(3, 18),
// (3,18): error CS0026: Keyword 'this' is not valid in a static property, static method, or static field initializer
// var r1 = new C { this.a = ref x }; // 1
Diagnostic(ErrorCode.ERR_ThisInStaticMeth, "this").WithLocation(3, 18),
// (7,32): warning CS0067: The event 'C.a' is never used
// public event System.Action a;
Diagnostic(ErrorCode.WRN_UnreferencedEvent, "a").WithArguments("C.a").WithLocation(7, 32)
);
}
[Fact]
public void RefInitializer_OnMethodGroup()
{
var source = @"
int x = 42;
var r = new C { F = ref x }; // 1
C c = default;
c.F = ref x; // 2
class C
{
public void F() { }
}
";
var comp = CreateCompilation(source);
comp.VerifyDiagnostics(
// (3,17): error CS1913: Member 'F' cannot be initialized. It is not a field or property.
// var r = new C { F = ref x }; // 1
Diagnostic(ErrorCode.ERR_MemberCannotBeInitialized, "F").WithArguments("F").WithLocation(3, 17),
// (6,1): error CS1656: Cannot assign to 'F' because it is a 'method group'
// c.F = ref x; // 2
Diagnostic(ErrorCode.ERR_AssgReadonlyLocalCause, "c.F").WithArguments("F", "method group").WithLocation(6, 1)
);
}
[Fact]
public void RefInitializer_Nested()
{
var source = @"
class C
{
static void Main()
{
int x = 42;
var r = new Container { item = { field = ref x } };
System.Console.Write(r.item.field);
}
}
ref struct Container
{
public Item item;
}
ref struct Item
{
public ref int field;
}
";
var comp = CreateCompilation(source, options: TestOptions.ReleaseExe, targetFramework: TargetFramework.Net70);
comp.VerifyDiagnostics();
var verifier = CompileAndVerify(comp, verify: Verification.Skipped, expectedOutput: IncludeExpectedOutput("42"));
verifier.VerifyIL("C.Main", @"
{
// Code size 43 (0x2b)
.maxstack 2
.locals init (int V_0, //x
Container V_1)
IL_0000: ldc.i4.s 42
IL_0002: stloc.0
IL_0003: ldloca.s V_1
IL_0005: initobj ""Container""
IL_000b: ldloca.s V_1
IL_000d: ldflda ""Item Container.item""
IL_0012: ldloca.s V_0
IL_0014: stfld ""ref int Item.field""
IL_0019: ldloc.1
IL_001a: ldfld ""Item Container.item""
IL_001f: ldfld ""ref int Item.field""
IL_0024: ldind.i4
IL_0025: call ""void System.Console.Write(int)""
IL_002a: ret
}
");
}
[Fact]
public void RefInitializer_Nullability()
{
var source = @"
#nullable enable
S<object> x1 = default;
S<object?> x2 = default;
_ = new R<object> { field = ref x1 };
_ = new R<object> { field = ref x2 }; // 1
_ = new R<object?> { field = ref x1 }; // 2
_ = new R<object?> { field = ref x2 };
_ = new R<object>() with { field = ref x1 };
_ = new R<object>() with { field = ref x2 }; // 3
_ = new R<object?>() with { field = ref x1 }; // 4
_ = new R<object?>() with { field = ref x2 };
struct S<T> { }
ref struct R<T>
{
public ref S<T> field;
}
";
var comp = CreateCompilation(source, options: TestOptions.ReleaseExe, targetFramework: TargetFramework.Net70);
comp.VerifyDiagnostics(
// (8,33): warning CS8619: Nullability of reference types in value of type 'S<object?>' doesn't match target type 'S<object>'.
// _ = new R<object> { field = ref x2 }; // 1
Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "x2").WithArguments("S<object?>", "S<object>").WithLocation(8, 33),
// (9,34): warning CS8619: Nullability of reference types in value of type 'S<object>' doesn't match target type 'S<object?>'.
// _ = new R<object?> { field = ref x1 }; // 2
Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "x1").WithArguments("S<object>", "S<object?>").WithLocation(9, 34),
// (13,40): warning CS8619: Nullability of reference types in value of type 'S<object?>' doesn't match target type 'S<object>'.
// _ = new R<object>() with { field = ref x2 }; // 3
Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "x2").WithArguments("S<object?>", "S<object>").WithLocation(13, 40),
// (14,41): warning CS8619: Nullability of reference types in value of type 'S<object>' doesn't match target type 'S<object?>'.
// _ = new R<object?>() with { field = ref x1 }; // 4
Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "x1").WithArguments("S<object>", "S<object?>").WithLocation(14, 41)
);
}
[Fact]
public void RefInitializer_RefOnNestedInitializer()
{
var source = @"
int x = 42;
var r = new R { field = ref { item = 42 } }; // 1
struct S
{
public int item;
}
ref struct R
{
public ref S field;
}
";
var comp = CreateCompilation(source, options: TestOptions.ReleaseExe, targetFramework: TargetFramework.Net70);
comp.VerifyDiagnostics(
// (2,5): warning CS0219: The variable 'x' is assigned but its value is never used
// int x = 42;
Diagnostic(ErrorCode.WRN_UnreferencedVarAssg, "x").WithArguments("x").WithLocation(2, 5),
// (3,29): error CS1525: Invalid expression term '{'
// var r = new R { field = ref { item = 42 } }; // 1
Diagnostic(ErrorCode.ERR_InvalidExprTerm, "{").WithArguments("{").WithLocation(3, 29),
// (3,29): error CS1003: Syntax error, ',' expected
// var r = new R { field = ref { item = 42 } }; // 1
Diagnostic(ErrorCode.ERR_SyntaxError, "{").WithArguments(",").WithLocation(3, 29),
// (3,29): error CS0747: Invalid initializer member declarator
// var r = new R { field = ref { item = 42 } }; // 1
Diagnostic(ErrorCode.ERR_InvalidInitializerElementInitializer, "{ item = 42 }").WithLocation(3, 29),
// (3,31): error CS0103: The name 'item' does not exist in the current context
// var r = new R { field = ref { item = 42 } }; // 1
Diagnostic(ErrorCode.ERR_NameNotInContext, "item").WithArguments("item").WithLocation(3, 31)
);
}
[Fact]
public void RefInitializer_FieldOnDynamic()
{
var source = @"
int x = 42;
var r = new S { D = { field = ref x } }; // 1
S s = default;
s.D.field = ref x; // 2
struct S
{
public dynamic D;
}
";
var comp = CreateCompilation(source);
comp.VerifyDiagnostics(
// (3,23): error CS8373: The left-hand side of a ref assignment must be a ref variable.
// var r = new S { D = { field = ref x } }; // 1
Diagnostic(ErrorCode.ERR_RefLocalOrParamExpected, "field").WithLocation(3, 23),
// (6,1): error CS8373: The left-hand side of a ref assignment must be a ref variable.
// s.D.field = ref x; // 2
Diagnostic(ErrorCode.ERR_RefLocalOrParamExpected, "s.D.field").WithLocation(6, 1)
);
}
[Fact]
public void RefInitializer_DynamicField()
{
var source = @"
int i = 42;
var r = new R<dynamic> { F = ref i }; // 1
ref struct R<T>
{
public ref T F;
}
";
var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70);
comp.VerifyDiagnostics(
// (3,34): error CS8173: The expression must be of type 'dynamic' because it is being assigned by reference
// var r = new R<dynamic> { F = ref i }; // 1
Diagnostic(ErrorCode.ERR_RefAssignmentMustHaveIdentityConversion, "i").WithArguments("dynamic").WithLocation(3, 34)
);
}
[Fact]
public void RefInitializer_DynamicField_DynamicValue()
{
var source = @"
public class C
{
public static void Main()
{
dynamic i = 42;
var r = new R<dynamic> { F = ref i };
System.Console.Write(r.F);
var r2 = new R<dynamic>(ref i);
System.Console.Write(r2.F);
}
}
ref struct R<T>
{
public R(ref T f) { F = ref f; }
public ref T F;
}
";
var references = TargetFrameworkUtil.GetReferences(TargetFramework.NetCoreApp, additionalReferences: null);
var comp = CreateCompilation(source, options: TestOptions.DebugExe, targetFramework: TargetFramework.Net70);
var verifier = CompileAndVerify(comp, verify: Verification.Skipped, expectedOutput: IncludeExpectedOutput("4242"));
verifier.VerifyIL("C.Main", """
{
// Code size 257 (0x101)
.maxstack 9
.locals init (object V_0, //i
R<dynamic> V_1, //r
R<dynamic> V_2, //r2
R<dynamic> V_3)
IL_0000: nop
IL_0001: ldc.i4.s 42
IL_0003: box "int"
IL_0008: stloc.0
IL_0009: ldloca.s V_3
IL_000b: initobj "R<dynamic>"
IL_0011: ldloca.s V_3
IL_0013: ldloca.s V_0
IL_0015: stfld "ref dynamic R<dynamic>.F"
IL_001a: ldloc.3
IL_001b: stloc.1
IL_001c: ldsfld "System.Runtime.CompilerServices.CallSite<System.Action<System.Runtime.CompilerServices.CallSite, System.Type, dynamic>> C.<>o__0.<>p__0"
IL_0021: brfalse.s IL_0025
IL_0023: br.s IL_0064
IL_0025: ldc.i4 0x100
IL_002a: ldstr "Write"
IL_002f: ldnull
IL_0030: ldtoken "C"
IL_0035: call "System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"
IL_003a: ldc.i4.2
IL_003b: newarr "Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo"
IL_0040: dup
IL_0041: ldc.i4.0
IL_0042: ldc.i4.s 33
IL_0044: ldnull
IL_0045: call "Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo.Create(Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfoFlags, string)"
IL_004a: stelem.ref
IL_004b: dup
IL_004c: ldc.i4.1
IL_004d: ldc.i4.0
IL_004e: ldnull
IL_004f: call "Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo.Create(Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfoFlags, string)"
IL_0054: stelem.ref
IL_0055: call "System.Runtime.CompilerServices.CallSiteBinder Microsoft.CSharp.RuntimeBinder.Binder.InvokeMember(Microsoft.CSharp.RuntimeBinder.CSharpBinderFlags, string, System.Collections.Generic.IEnumerable<System.Type>, System.Type, System.Collections.Generic.IEnumerable<Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo>)"
IL_005a: call "System.Runtime.CompilerServices.CallSite<System.Action<System.Runtime.CompilerServices.CallSite, System.Type, dynamic>> System.Runtime.CompilerServices.CallSite<System.Action<System.Runtime.CompilerServices.CallSite, System.Type, dynamic>>.Create(System.Runtime.CompilerServices.CallSiteBinder)"
IL_005f: stsfld "System.Runtime.CompilerServices.CallSite<System.Action<System.Runtime.CompilerServices.CallSite, System.Type, dynamic>> C.<>o__0.<>p__0"
IL_0064: ldsfld "System.Runtime.CompilerServices.CallSite<System.Action<System.Runtime.CompilerServices.CallSite, System.Type, dynamic>> C.<>o__0.<>p__0"
IL_0069: ldfld "System.Action<System.Runtime.CompilerServices.CallSite, System.Type, dynamic> System.Runtime.CompilerServices.CallSite<System.Action<System.Runtime.CompilerServices.CallSite, System.Type, dynamic>>.Target"
IL_006e: ldsfld "System.Runtime.CompilerServices.CallSite<System.Action<System.Runtime.CompilerServices.CallSite, System.Type, dynamic>> C.<>o__0.<>p__0"
IL_0073: ldtoken "System.Console"
IL_0078: call "System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"
IL_007d: ldloc.1
IL_007e: ldfld "ref dynamic R<dynamic>.F"
IL_0083: ldind.ref
IL_0084: callvirt "void System.Action<System.Runtime.CompilerServices.CallSite, System.Type, dynamic>.Invoke(System.Runtime.CompilerServices.CallSite, System.Type, dynamic)"
IL_0089: nop
IL_008a: ldloca.s V_0
IL_008c: newobj "R<dynamic>..ctor(ref dynamic)"
IL_0091: stloc.2
IL_0092: ldsfld "System.Runtime.CompilerServices.CallSite<System.Action<System.Runtime.CompilerServices.CallSite, System.Type, dynamic>> C.<>o__0.<>p__1"
IL_0097: brfalse.s IL_009b
IL_0099: br.s IL_00da
IL_009b: ldc.i4 0x100
IL_00a0: ldstr "Write"
IL_00a5: ldnull
IL_00a6: ldtoken "C"
IL_00ab: call "System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"
IL_00b0: ldc.i4.2
IL_00b1: newarr "Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo"
IL_00b6: dup
IL_00b7: ldc.i4.0
IL_00b8: ldc.i4.s 33
IL_00ba: ldnull
IL_00bb: call "Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo.Create(Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfoFlags, string)"
IL_00c0: stelem.ref
IL_00c1: dup
IL_00c2: ldc.i4.1
IL_00c3: ldc.i4.0
IL_00c4: ldnull
IL_00c5: call "Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo.Create(Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfoFlags, string)"
IL_00ca: stelem.ref
IL_00cb: call "System.Runtime.CompilerServices.CallSiteBinder Microsoft.CSharp.RuntimeBinder.Binder.InvokeMember(Microsoft.CSharp.RuntimeBinder.CSharpBinderFlags, string, System.Collections.Generic.IEnumerable<System.Type>, System.Type, System.Collections.Generic.IEnumerable<Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo>)"
IL_00d0: call "System.Runtime.CompilerServices.CallSite<System.Action<System.Runtime.CompilerServices.CallSite, System.Type, dynamic>> System.Runtime.CompilerServices.CallSite<System.Action<System.Runtime.CompilerServices.CallSite, System.Type, dynamic>>.Create(System.Runtime.CompilerServices.CallSiteBinder)"
IL_00d5: stsfld "System.Runtime.CompilerServices.CallSite<System.Action<System.Runtime.CompilerServices.CallSite, System.Type, dynamic>> C.<>o__0.<>p__1"
IL_00da: ldsfld "System.Runtime.CompilerServices.CallSite<System.Action<System.Runtime.CompilerServices.CallSite, System.Type, dynamic>> C.<>o__0.<>p__1"
IL_00df: ldfld "System.Action<System.Runtime.CompilerServices.CallSite, System.Type, dynamic> System.Runtime.CompilerServices.CallSite<System.Action<System.Runtime.CompilerServices.CallSite, System.Type, dynamic>>.Target"
IL_00e4: ldsfld "System.Runtime.CompilerServices.CallSite<System.Action<System.Runtime.CompilerServices.CallSite, System.Type, dynamic>> C.<>o__0.<>p__1"
IL_00e9: ldtoken "System.Console"
IL_00ee: call "System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"
IL_00f3: ldloc.2
IL_00f4: ldfld "ref dynamic R<dynamic>.F"
IL_00f9: ldind.ref
IL_00fa: callvirt "void System.Action<System.Runtime.CompilerServices.CallSite, System.Type, dynamic>.Invoke(System.Runtime.CompilerServices.CallSite, System.Type, dynamic)"
IL_00ff: nop
IL_0100: ret
}
""");
}
[Fact]
public void RefInitializer_SubstitutedObjectField()
{
var source = @"
public class C
{
public static void Main()
{
object i = 42;
var r = new R<object> { F = ref i };
System.Console.Write(r.F);
var r2 = new R<object>(ref i);
System.Console.Write(r2.F);
}
}
ref struct R<T>
{
public R(ref T f) { F = ref f; }
public ref T F;
}
";
var comp = CreateCompilation(source, options: TestOptions.DebugExe, targetFramework: TargetFramework.Net70);
comp.VerifyDiagnostics();
comp = CreateCompilation(source, options: TestOptions.ReleaseExe, targetFramework: TargetFramework.Net70);
var verifier = CompileAndVerify(comp, verify: Verification.Skipped, expectedOutput: IncludeExpectedOutput("4242"));
verifier.VerifyIL("C.Main", """
{
// Code size 56 (0x38)
.maxstack 2
.locals init (object V_0, //i
R<object> V_1)
IL_0000: ldc.i4.s 42
IL_0002: box "int"
IL_0007: stloc.0
IL_0008: ldloca.s V_1
IL_000a: initobj "R<object>"
IL_0010: ldloca.s V_1
IL_0012: ldloca.s V_0
IL_0014: stfld "ref object R<object>.F"
IL_0019: ldloc.1
IL_001a: ldfld "ref object R<object>.F"
IL_001f: ldind.ref
IL_0020: call "void System.Console.Write(object)"
IL_0025: ldloca.s V_0
IL_0027: newobj "R<object>..ctor(ref object)"
IL_002c: ldfld "ref object R<object>.F"
IL_0031: ldind.ref
IL_0032: call "void System.Console.Write(object)"
IL_0037: ret
}
""");
}
[Fact]
public void RefInitializer_DynamicInstance()
{
var source = @"
int x = 42;
var r = new dynamic { field = ref x }; // 1
dynamic r2 = null;
r2.field = ref x; // 2
";
var comp = CreateCompilation(source);
comp.VerifyDiagnostics(
// (3,13): error CS8386: Invalid object creation
// var r = new dynamic { field = ref x }; // 1
Diagnostic(ErrorCode.ERR_InvalidObjectCreation, "dynamic").WithLocation(3, 13),
// (3,23): error CS8373: The left-hand side of a ref assignment must be a ref variable.
// var r = new dynamic { field = ref x }; // 1
Diagnostic(ErrorCode.ERR_RefLocalOrParamExpected, "field").WithLocation(3, 23),
// (6,1): error CS8373: The left-hand side of a ref assignment must be a ref variable.
// r2.field = ref x; // 2
Diagnostic(ErrorCode.ERR_RefLocalOrParamExpected, "r2.field").WithLocation(6, 1)
);
}
[Fact]
public void RefInitializer_DynamicIndexer()
{
var source = @"
int x = 42;
var r = new S { D = { [0] = ref x } }; // 1
S s = default;
s.D[0] = ref x; // 2
struct S
{
public dynamic D;
}
ref struct R
{
}
";
var comp = CreateCompilation(source);
comp.VerifyDiagnostics(
// (3,23): error CS8373: The left-hand side of a ref assignment must be a ref variable.
// var r = new S { D = { [0] = ref x } }; // 1
Diagnostic(ErrorCode.ERR_RefLocalOrParamExpected, "[0]").WithLocation(3, 23),
// (6,1): error CS8373: The left-hand side of a ref assignment must be a ref variable.
// s.D[0] = ref x; // 2
Diagnostic(ErrorCode.ERR_RefLocalOrParamExpected, "s.D[0]").WithLocation(6, 1)
);
}
[Fact]
public void RefInitializer_DynamicIndexer_Nested()
{
var source = @"
dynamic x = 1;
int i = 42;
var a = new A() { [y: x, x: x] = { X = ref i } }; // 1
A a2 = null;
a2[y: x, x: x].X = ref i; // 2
public class A
{
public dynamic this[int x, int y] { get => throw null; }
}
";
var comp = CreateCompilation(source);
comp.VerifyDiagnostics(
// (4,36): error CS8373: The left-hand side of a ref assignment must be a ref variable.
// var a = new A() { [y: x, x: x] = { X = ref i } }; // 1
Diagnostic(ErrorCode.ERR_RefLocalOrParamExpected, "X").WithLocation(4, 36),
// (7,1): error CS8373: The left-hand side of a ref assignment must be a ref variable.
// a2[y: x, x: x].X = ref i; // 2
Diagnostic(ErrorCode.ERR_RefLocalOrParamExpected, "a2[y: x, x: x].X").WithLocation(7, 1)
);
}
[Fact]
public void RefInitializer_Escape()
{
var source = @"
public class C
{
public static R M1()
{
int x = 42;
var r = new R { field = ref x };
return r; // 1
}
public static R M2(ref int x)
{
var r = new R { field = ref x };
return r;
}
public static R M3()
{
R r = default;
{
int x = 42;
r = new R { field = ref x }; // 2
}
return r;
}
public static R M4()
{
R r = default;
int x = 42;
{
r = new R { field = ref x }; // 3
}
return r;
}
public static void M5(ref R r)
{
int x = 42;
r = new R { field = ref x }; // 4
}
}
public ref struct R
{
public ref int field;
}
";
var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70);
comp.VerifyDiagnostics(
// (8,16): error CS8352: Cannot use variable 'r' in this context because it may expose referenced variables outside of their declaration scope
// return r; // 1
Diagnostic(ErrorCode.ERR_EscapeVariable, "r").WithArguments("r").WithLocation(8, 16),
// (20,25): error CS8168: Cannot return local 'x' by reference because it is not a ref local
// r = new R { field = ref x }; // 2
Diagnostic(ErrorCode.ERR_RefReturnLocal, "field = ref x").WithArguments("x").WithLocation(20, 25),
// (29,25): error CS8168: Cannot return local 'x' by reference because it is not a ref local
// r = new R { field = ref x }; // 3
Diagnostic(ErrorCode.ERR_RefReturnLocal, "field = ref x").WithArguments("x").WithLocation(29, 25),
// (36,21): error CS8168: Cannot return local 'x' by reference because it is not a ref local
// r = new R { field = ref x }; // 4
Diagnostic(ErrorCode.ERR_RefReturnLocal, "field = ref x").WithArguments("x").WithLocation(36, 21)
);
// Initializer values behave like constructor parameters for purpose of escape analysis
source = @"
public class C
{
public static R M1()
{
int x = 42;
var r = new R(ref x);
return r; // 1
}
public static R M2(ref int x)
{
var r = new R(ref x);
return r;
}
public static R M3()
{
R r = default;
{
int x = 42;
r = new R(ref x); // 2
}
return r;
}
public static R M4()
{
R r = default;
int x = 42;
{
r = new R(ref x); // 3
}
return r;
}
public static void M5(ref R r)
{
int x = 42;
r = new R(ref x); // 4
}
}
public ref struct R
{
public ref int field;
public R(ref int i) { }
}
";
comp = CreateCompilation(source, targetFramework: TargetFramework.Net70);
comp.VerifyDiagnostics(
// (8,16): error CS8352: Cannot use variable 'r' in this context because it may expose referenced variables outside of their declaration scope
// return r; // 1
Diagnostic(ErrorCode.ERR_EscapeVariable, "r").WithArguments("r").WithLocation(8, 16),
// (20,17): error CS8347: Cannot use a result of 'R.R(ref int)' in this context because it may expose variables referenced by parameter 'i' outside of their declaration scope
// r = new R(ref x); // 2
Diagnostic(ErrorCode.ERR_EscapeCall, "new R(ref x)").WithArguments("R.R(ref int)", "i").WithLocation(20, 17),
// (20,27): error CS8168: Cannot return local 'x' by reference because it is not a ref local
// r = new R(ref x); // 2
Diagnostic(ErrorCode.ERR_RefReturnLocal, "x").WithArguments("x").WithLocation(20, 27),
// (29,17): error CS8347: Cannot use a result of 'R.R(ref int)' in this context because it may expose variables referenced by parameter 'i' outside of their declaration scope
// r = new R(ref x); // 3
Diagnostic(ErrorCode.ERR_EscapeCall, "new R(ref x)").WithArguments("R.R(ref int)", "i").WithLocation(29, 17),
// (29,27): error CS8168: Cannot return local 'x' by reference because it is not a ref local
// r = new R(ref x); // 3
Diagnostic(ErrorCode.ERR_RefReturnLocal, "x").WithArguments("x").WithLocation(29, 27),
// (36,13): error CS8347: Cannot use a result of 'R.R(ref int)' in this context because it may expose variables referenced by parameter 'i' outside of their declaration scope
// r = new R(ref x); // 4
Diagnostic(ErrorCode.ERR_EscapeCall, "new R(ref x)").WithArguments("R.R(ref int)", "i").WithLocation(36, 13),
// (36,23): error CS8168: Cannot return local 'x' by reference because it is not a ref local
// r = new R(ref x); // 4
Diagnostic(ErrorCode.ERR_RefReturnLocal, "x").WithArguments("x").WithLocation(36, 23)
);
}
[Fact]
public void RefInitializer_Escape_Nested()
{
var source = @"
class C
{
public static Container M3()
{
Container r = default;
{
int x = 42;
var r = new Container { item = { field = ref x } }; // 1
}
return r;
}
public static Container M4()
{
Container r = default;
int x = 42;
{
r = new Container { item = { field = ref x } }; // 2
}
return r;
}
public static void M5(ref Container r)
{
int x = 42;
r = new Container { item = { field = ref x } }; // 3
}
public static Container M6()
{
int x = 42;
var r = new Container { item = { field = ref x } };
return r; // 4
}
}
ref struct Container
{
public Item item;
}
ref struct Item
{
public ref int field;
}
";
var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70);
comp.VerifyDiagnostics(
// (9,17): error CS0136: A local or parameter named 'r' cannot be declared in this scope because that name is used in an enclosing local scope to define a local or parameter
// var r = new Container { item = { field = ref x } }; // 1
Diagnostic(ErrorCode.ERR_LocalIllegallyOverrides, "r").WithArguments("r").WithLocation(9, 17),
// (18,42): error CS8168: Cannot return local 'x' by reference because it is not a ref local
// r = new Container { item = { field = ref x } }; // 2
Diagnostic(ErrorCode.ERR_RefReturnLocal, "field = ref x").WithArguments("x").WithLocation(18, 42),
// (25,38): error CS8168: Cannot return local 'x' by reference because it is not a ref local
// r = new Container { item = { field = ref x } }; // 3
Diagnostic(ErrorCode.ERR_RefReturnLocal, "field = ref x").WithArguments("x").WithLocation(25, 38),
// (31,16): error CS8352: Cannot use variable 'r' in this context because it may expose referenced variables outside of their declaration scope
// return r; // 4
Diagnostic(ErrorCode.ERR_EscapeVariable, "r").WithArguments("r").WithLocation(31, 16)
);
}
[Fact]
public void RefWith()
{
var source = @"
public class C
{
public static void Main()
{
int x = 42;
var r = new R() with { field = ref x };
System.Console.Write(r.ToString());
}
}
ref struct R
{
public ref int field;
public override string ToString()
{
return field.ToString();
}
}
";
var comp = CreateCompilation(source, options: TestOptions.ReleaseExe, targetFramework: TargetFramework.Net70);
comp.VerifyDiagnostics();
var verifier = CompileAndVerify(comp, verify: Verification.Skipped, expectedOutput: IncludeExpectedOutput("42"));
verifier.VerifyIL("C.Main",
"""
{
// Code size 41 (0x29)
.maxstack 2
.locals init (int V_0, //x
R V_1, //r
R V_2)
IL_0000: ldc.i4.s 42
IL_0002: stloc.0
IL_0003: ldloca.s V_2
IL_0005: initobj "R"
IL_000b: ldloca.s V_2
IL_000d: ldloca.s V_0
IL_000f: stfld "ref int R.field"
IL_0014: ldloc.2
IL_0015: stloc.1
IL_0016: ldloca.s V_1
IL_0018: constrained. "R"
IL_001e: callvirt "string object.ToString()"
IL_0023: call "void System.Console.Write(string)"
IL_0028: ret
}
""");
}
[Fact]
public void RefWith_Escape()
{
var source = @"
public class C
{
public static R M1()
{
int x = 42;
var r = new R() with { field = ref x };
return r; // 1
}
public static R M2(ref int x)
{
var r = new R() with { field = ref x };
return r;
}
public static R M3()
{
R r = default;
{
int x = 42;
r = new R() with { field = ref x }; // 2
}
return r;
}
public static R M4()
{
R r = default;
int x = 42;
{
r = new R() with { field = ref x }; // 3
}
return r;
}
public static void M5(ref R r)
{
int x = 42;
r = new R() with { field = ref x }; // 4
}
}
public ref struct R
{
public ref int field;
}
";
var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70);
comp.VerifyDiagnostics(
// (8,16): error CS8352: Cannot use variable 'r' in this context because it may expose referenced variables outside of their declaration scope
// return r; // 1
Diagnostic(ErrorCode.ERR_EscapeVariable, "r").WithArguments("r").WithLocation(8, 16),
// (20,32): error CS8168: Cannot return local 'x' by reference because it is not a ref local
// r = new R() with { field = ref x }; // 2
Diagnostic(ErrorCode.ERR_RefReturnLocal, "field = ref x").WithArguments("x").WithLocation(20, 32),
// (29,32): error CS8168: Cannot return local 'x' by reference because it is not a ref local
// r = new R() with { field = ref x }; // 3
Diagnostic(ErrorCode.ERR_RefReturnLocal, "field = ref x").WithArguments("x").WithLocation(29, 32),
// (36,28): error CS8168: Cannot return local 'x' by reference because it is not a ref local
// r = new R() with { field = ref x }; // 4
Diagnostic(ErrorCode.ERR_RefReturnLocal, "field = ref x").WithArguments("x").WithLocation(36, 28)
);
}
[Fact]
public void RefScoped()
{
var source =
@"ref struct R
{
ref scoped R field;
}";
var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70);
comp.VerifyDiagnostics(
// (3,9): error CS0246: The type or namespace name 'scoped' could not be found (are you missing a using directive or an assembly reference?)
// ref scoped R field;
Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "scoped").WithArguments("scoped").WithLocation(3, 9),
// (3,16): error CS0542: 'R': member names cannot be the same as their enclosing type
// ref scoped R field;
Diagnostic(ErrorCode.ERR_MemberNameSameAsType, "R").WithArguments("R").WithLocation(3, 16),
// (3,16): warning CS0169: The field 'R.R' is never used
// ref scoped R field;
Diagnostic(ErrorCode.WRN_UnreferencedField, "R").WithArguments("R.R").WithLocation(3, 16),
// (3,18): error CS1002: ; expected
// ref scoped R field;
Diagnostic(ErrorCode.ERR_SemicolonExpected, "field").WithLocation(3, 18),
// (3,23): error CS1519: Invalid token ';' in class, record, struct, or interface member declaration
// ref scoped R field;
Diagnostic(ErrorCode.ERR_InvalidMemberDecl, ";").WithArguments(";").WithLocation(3, 23),
// (3,23): error CS1519: Invalid token ';' in class, record, struct, or interface member declaration
// ref scoped R field;
Diagnostic(ErrorCode.ERR_InvalidMemberDecl, ";").WithArguments(";").WithLocation(3, 23)
);
source =
@"ref struct R
{
ref scoped R Property { get => throw null; }
}";
comp = CreateCompilation(source);
comp.VerifyDiagnostics(
// (3,9): error CS0246: The type or namespace name 'scoped' could not be found (are you missing a using directive or an assembly reference?)
// ref scoped R Property { get => throw null; }
Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "scoped").WithArguments("scoped").WithLocation(3, 9),
// (3,16): error CS9064: Target runtime doesn't support ref fields.
// ref scoped R Property { get => throw null; }
Diagnostic(ErrorCode.ERR_RuntimeDoesNotSupportRefFields, "R").WithLocation(3, 16),
// (3,16): error CS0542: 'R': member names cannot be the same as their enclosing type
// ref scoped R Property { get => throw null; }
Diagnostic(ErrorCode.ERR_MemberNameSameAsType, "R").WithArguments("R").WithLocation(3, 16),
// (3,16): warning CS0169: The field 'R.R' is never used
// ref scoped R Property { get => throw null; }
Diagnostic(ErrorCode.WRN_UnreferencedField, "R").WithArguments("R.R").WithLocation(3, 16),
// (3,18): error CS1002: ; expected
// ref scoped R Property { get => throw null; }
Diagnostic(ErrorCode.ERR_SemicolonExpected, "Property").WithLocation(3, 18),
// (3,27): error CS1519: Invalid token '{' in class, record, struct, or interface member declaration
// ref scoped R Property { get => throw null; }
Diagnostic(ErrorCode.ERR_InvalidMemberDecl, "{").WithArguments("{").WithLocation(3, 27),
// (3,27): error CS1519: Invalid token '{' in class, record, struct, or interface member declaration
// ref scoped R Property { get => throw null; }
Diagnostic(ErrorCode.ERR_InvalidMemberDecl, "{").WithArguments("{").WithLocation(3, 27),
// (3,33): error CS1519: Invalid token '=>' in class, record, struct, or interface member declaration
// ref scoped R Property { get => throw null; }
Diagnostic(ErrorCode.ERR_InvalidMemberDecl, "=>").WithArguments("=>").WithLocation(3, 33),
// (3,33): error CS1519: Invalid token '=>' in class, record, struct, or interface member declaration
// ref scoped R Property { get => throw null; }
Diagnostic(ErrorCode.ERR_InvalidMemberDecl, "=>").WithArguments("=>").WithLocation(3, 33),
// (4,1): error CS1022: Type or namespace definition, or end-of-file expected
// }
Diagnostic(ErrorCode.ERR_EOFExpected, "}").WithLocation(4, 1)
);
source =
@"ref struct R
{
void M(ref scoped R parameter)
{
}
}";
comp = CreateCompilation(source);
comp.VerifyDiagnostics(
// (3,16): error CS0246: The type or namespace name 'scoped' could not be found (are you missing a using directive or an assembly reference?)
// void M(ref scoped R parameter)
Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "scoped").WithArguments("scoped").WithLocation(3, 16),
// (3,25): error CS1003: Syntax error, ',' expected
// void M(ref scoped R parameter)
Diagnostic(ErrorCode.ERR_SyntaxError, "parameter").WithArguments(",").WithLocation(3, 25),
// (3,25): error CS0246: The type or namespace name 'parameter' could not be found (are you missing a using directive or an assembly reference?)
// void M(ref scoped R parameter)
Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "parameter").WithArguments("parameter").WithLocation(3, 25),
// (3,34): error CS1001: Identifier expected
// void M(ref scoped R parameter)
Diagnostic(ErrorCode.ERR_IdentifierExpected, ")").WithLocation(3, 34)
);
source =
@"ref struct R
{
void M(in scoped R parameter)
{
}
}";
comp = CreateCompilation(source);
comp.VerifyDiagnostics(
// (3,15): error CS0246: The type or namespace name 'scoped' could not be found (are you missing a using directive or an assembly reference?)
// void M(in scoped R parameter)
Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "scoped").WithArguments("scoped").WithLocation(3, 15),
// (3,24): error CS1003: Syntax error, ',' expected
// void M(in scoped R parameter)
Diagnostic(ErrorCode.ERR_SyntaxError, "parameter").WithArguments(",").WithLocation(3, 24),
// (3,24): error CS0246: The type or namespace name 'parameter' could not be found (are you missing a using directive or an assembly reference?)
// void M(in scoped R parameter)
Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "parameter").WithArguments("parameter").WithLocation(3, 24),
// (3,33): error CS1001: Identifier expected
// void M(in scoped R parameter)
Diagnostic(ErrorCode.ERR_IdentifierExpected, ")").WithLocation(3, 33)
);
source =
@"ref struct R
{
void M(out scoped R parameter)
{
}
}";
comp = CreateCompilation(source);
comp.VerifyDiagnostics(
// (3,10): error CS0177: The out parameter 'R' must be assigned to before control leaves the current method
// void M(out scoped R parameter)
Diagnostic(ErrorCode.ERR_ParamUnassigned, "M").WithArguments("R").WithLocation(3, 10),
// (3,16): error CS0246: The type or namespace name 'scoped' could not be found (are you missing a using directive or an assembly reference?)
// void M(out scoped R parameter)
Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "scoped").WithArguments("scoped").WithLocation(3, 16),
// (3,25): error CS1003: Syntax error, ',' expected
// void M(out scoped R parameter)
Diagnostic(ErrorCode.ERR_SyntaxError, "parameter").WithArguments(",").WithLocation(3, 25),
// (3,25): error CS0246: The type or namespace name 'parameter' could not be found (are you missing a using directive or an assembly reference?)
// void M(out scoped R parameter)
Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "parameter").WithArguments("parameter").WithLocation(3, 25),
// (3,34): error CS1001: Identifier expected
// void M(out scoped R parameter)
Diagnostic(ErrorCode.ERR_IdentifierExpected, ")").WithLocation(3, 34)
);
source =
@"ref struct R
{
void M(ref scoped scoped R parameter)
{
}
}";
comp = CreateCompilation(source);
comp.VerifyDiagnostics(
// (3,16): error CS0246: The type or namespace name 'scoped' could not be found (are you missing a using directive or an assembly reference?)
// void M(ref scoped scoped R parameter)
Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "scoped").WithArguments("scoped").WithLocation(3, 16),
// (3,30): error CS1003: Syntax error, ',' expected
// void M(ref scoped scoped R parameter)
Diagnostic(ErrorCode.ERR_SyntaxError, "R").WithArguments(",").WithLocation(3, 30)
);
source =
@"ref struct R
{
void M()
{
ref scoped R local;
}
}";
comp = CreateCompilation(source);
comp.VerifyDiagnostics(
// (5,13): error CS0246: The type or namespace name 'scoped' could not be found (are you missing a using directive or an assembly reference?)
// ref scoped R local;
Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "scoped").WithArguments("scoped").WithLocation(5, 13),
// (5,20): error CS8174: A declaration of a by-reference variable must have an initializer
// ref scoped R local;
Diagnostic(ErrorCode.ERR_ByReferenceVariableMustBeInitialized, "R").WithLocation(5, 20),
// (5,20): warning CS0168: The variable 'R' is declared but never used
// ref scoped R local;
Diagnostic(ErrorCode.WRN_UnreferencedVar, "R").WithArguments("R").WithLocation(5, 20),
// (5,22): error CS1002: ; expected
// ref scoped R local;
Diagnostic(ErrorCode.ERR_SemicolonExpected, "local").WithLocation(5, 22),
// (5,22): error CS0103: The name 'local' does not exist in the current context
// ref scoped R local;
Diagnostic(ErrorCode.ERR_NameNotInContext, "local").WithArguments("local").WithLocation(5, 22),
// (5,22): error CS0201: Only assignment, call, increment, decrement, await, and new object expressions can be used as a statement
// ref scoped R local;
Diagnostic(ErrorCode.ERR_IllegalStatement, "local").WithLocation(5, 22)
);
source =
@"ref struct R
{
void M()
{
scoped ref scoped R local;
}
}";
comp = CreateCompilation(source);
comp.VerifyDiagnostics(
// (5,20): error CS0246: The type or namespace name 'scoped' could not be found (are you missing a using directive or an assembly reference?)
// scoped ref scoped R local;
Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "scoped").WithArguments("scoped").WithLocation(5, 20),
// (5,27): error CS8174: A declaration of a by-reference variable must have an initializer
// scoped ref scoped R local;
Diagnostic(ErrorCode.ERR_ByReferenceVariableMustBeInitialized, "R").WithLocation(5, 27),
// (5,27): warning CS0168: The variable 'R' is declared but never used
// scoped ref scoped R local;
Diagnostic(ErrorCode.WRN_UnreferencedVar, "R").WithArguments("R").WithLocation(5, 27),
// (5,29): error CS1002: ; expected
// scoped ref scoped R local;
Diagnostic(ErrorCode.ERR_SemicolonExpected, "local").WithLocation(5, 29),
// (5,29): error CS0103: The name 'local' does not exist in the current context
// scoped ref scoped R local;
Diagnostic(ErrorCode.ERR_NameNotInContext, "local").WithArguments("local").WithLocation(5, 29),
// (5,29): error CS0201: Only assignment, call, increment, decrement, await, and new object expressions can be used as a statement
// scoped ref scoped R local;
Diagnostic(ErrorCode.ERR_IllegalStatement, "local").WithLocation(5, 29)
);
source =
@"ref struct R
{
ref scoped R M() => throw null;
}";
comp = CreateCompilation(source);
comp.VerifyDiagnostics(
// (3,9): error CS0246: The type or namespace name 'scoped' could not be found (are you missing a using directive or an assembly reference?)
// ref scoped R M() => throw null;
Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "scoped").WithArguments("scoped").WithLocation(3, 9),
// (3,16): error CS9064: Target runtime doesn't support ref fields.
// ref scoped R M() => throw null;
Diagnostic(ErrorCode.ERR_RuntimeDoesNotSupportRefFields, "R").WithLocation(3, 16),
// (3,16): error CS0542: 'R': member names cannot be the same as their enclosing type
// ref scoped R M() => throw null;
Diagnostic(ErrorCode.ERR_MemberNameSameAsType, "R").WithArguments("R").WithLocation(3, 16),
// (3,16): warning CS0169: The field 'R.R' is never used
// ref scoped R M() => throw null;
Diagnostic(ErrorCode.WRN_UnreferencedField, "R").WithArguments("R.R").WithLocation(3, 16),
// (3,18): error CS1002: ; expected
// ref scoped R M() => throw null;
Diagnostic(ErrorCode.ERR_SemicolonExpected, "M").WithLocation(3, 18),
// (3,18): error CS1520: Method must have a return type
// ref scoped R M() => throw null;
Diagnostic(ErrorCode.ERR_MemberNeedsType, "M").WithLocation(3, 18),
// (3,18): error CS8958: The parameterless struct constructor must be 'public'.
// ref scoped R M() => throw null;
Diagnostic(ErrorCode.ERR_NonPublicParameterlessStructConstructor, "M").WithLocation(3, 18)
);
source = @"
delegate void M(ref scoped R parameter);
ref struct R { }
";
comp = CreateCompilation(source);
comp.VerifyDiagnostics(
// (2,21): error CS0246: The type or namespace name 'scoped' could not be found (are you missing a using directive or an assembly reference?)
// delegate void M(ref scoped R parameter);
Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "scoped").WithArguments("scoped").WithLocation(2, 21),
// (2,30): error CS1003: Syntax error, ',' expected
// delegate void M(ref scoped R parameter);
Diagnostic(ErrorCode.ERR_SyntaxError, "parameter").WithArguments(",").WithLocation(2, 30),
// (2,30): error CS0246: The type or namespace name 'parameter' could not be found (are you missing a using directive or an assembly reference?)
// delegate void M(ref scoped R parameter);
Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "parameter").WithArguments("parameter").WithLocation(2, 30),
// (2,39): error CS1001: Identifier expected
// delegate void M(ref scoped R parameter);
Diagnostic(ErrorCode.ERR_IdentifierExpected, ")").WithLocation(2, 39)
);
source = @"
ref struct R
{
void M()
{
_ = void (ref scoped R parameter) => throw null;
}
}
";
comp = CreateCompilation(source);
comp.VerifyDiagnostics(
// (6,13): error CS1525: Invalid expression term 'void'
// _ = void (ref scoped R parameter) => throw null;
Diagnostic(ErrorCode.ERR_InvalidExprTerm, "void").WithArguments("void").WithLocation(6, 13),
// (6,23): error CS0103: The name 'scoped' does not exist in the current context
// _ = void (ref scoped R parameter) => throw null;
Diagnostic(ErrorCode.ERR_NameNotInContext, "scoped").WithArguments("scoped").WithLocation(6, 23),
// (6,30): error CS1003: Syntax error, ',' expected
// _ = void (ref scoped R parameter) => throw null;
Diagnostic(ErrorCode.ERR_SyntaxError, "R").WithArguments(",").WithLocation(6, 30),
// (6,30): error CS0119: 'R' is a type, which is not valid in the given context
// _ = void (ref scoped R parameter) => throw null;
Diagnostic(ErrorCode.ERR_BadSKunknown, "R").WithArguments("R", "type").WithLocation(6, 30),
// (6,32): error CS1003: Syntax error, ',' expected
// _ = void (ref scoped R parameter) => throw null;
Diagnostic(ErrorCode.ERR_SyntaxError, "parameter").WithArguments(",").WithLocation(6, 32),
// (6,32): error CS0103: The name 'parameter' does not exist in the current context
// _ = void (ref scoped R parameter) => throw null;
Diagnostic(ErrorCode.ERR_NameNotInContext, "parameter").WithArguments("parameter").WithLocation(6, 32),
// (6,43): error CS1002: ; expected
// _ = void (ref scoped R parameter) => throw null;
Diagnostic(ErrorCode.ERR_SemicolonExpected, "=>").WithLocation(6, 43),
// (6,43): error CS1513: } expected
// _ = void (ref scoped R parameter) => throw null;
Diagnostic(ErrorCode.ERR_RbraceExpected, "=>").WithLocation(6, 43)
);
}
[Theory, WorkItem(62931, "https://github.com/dotnet/roslyn/issues/62931")]
[InlineData("class")]
[InlineData("struct")]
[InlineData("interface")]
[InlineData("enum")]
[InlineData("record")]
public void ScopedReserved_Type(string typeKind)
{
var source = $$"""
{{typeKind}} scoped { }
""";
var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10);
comp.VerifyDiagnostics(
// (1,8): warning CS8981: The type name 'scoped' only contains lower-cased ascii characters. Such names may become reserved for the language.
// struct scoped { }
Diagnostic(ErrorCode.WRN_LowerCaseTypeName, "scoped").WithArguments("scoped")
);
comp = CreateCompilation(source, parseOptions: TestOptions.Regular11);
comp.VerifyDiagnostics(
// (1,8): error CS9062: Types and aliases cannot be named 'scoped'.
// struct scoped { }
Diagnostic(ErrorCode.ERR_ScopedTypeNameDisallowed, "scoped")
);
}
[Fact, WorkItem(62931, "https://github.com/dotnet/roslyn/issues/62931")]
public void ScopedReserved_Type_Escaped()
{
var source = """
class @scoped { }
""";
var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10);
comp.VerifyDiagnostics();
comp = CreateCompilation(source, parseOptions: TestOptions.Regular11);
comp.VerifyDiagnostics();
}
[Fact, WorkItem(62931, "https://github.com/dotnet/roslyn/issues/62931")]
public void ScopedReserved_TypeParameter()
{
var source = """
class C<scoped> { } // 1
class C2<@scoped> { }
class D
{
void M()
{
local<object>();
void local<scoped>() { } // 2
}
void M2()
{
local<object>();
void local<@scoped>() { }
}
}
class D2
{
void M<scoped>() { } // 3
void M2<@scoped>() { }
}
""";
var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10);
comp.VerifyDiagnostics(
// (1,9): warning CS8981: The type name 'scoped' only contains lower-cased ascii characters. Such names may become reserved for the language.
// class C<scoped> { } // 1
Diagnostic(ErrorCode.WRN_LowerCaseTypeName, "scoped").WithArguments("scoped").WithLocation(1, 9),
// (9,20): warning CS8981: The type name 'scoped' only contains lower-cased ascii characters. Such names may become reserved for the language.
// void local<scoped>() { } // 2
Diagnostic(ErrorCode.WRN_LowerCaseTypeName, "scoped").WithArguments("scoped").WithLocation(9, 20),
// (21,12): warning CS8981: The type name 'scoped' only contains lower-cased ascii characters. Such names may become reserved for the language.
// void M<scoped>() { } // 3
Diagnostic(ErrorCode.WRN_LowerCaseTypeName, "scoped").WithArguments("scoped").WithLocation(21, 12)
);
comp = CreateCompilation(source, parseOptions: TestOptions.Regular11);
comp.VerifyDiagnostics(
// (1,9): error CS9062: Types and aliases cannot be named 'scoped'.
// class C<scoped> { } // 1
Diagnostic(ErrorCode.ERR_ScopedTypeNameDisallowed, "scoped").WithLocation(1, 9),
// (9,20): error CS9062: Types and aliases cannot be named 'scoped'.
// void local<scoped>() { } // 2
Diagnostic(ErrorCode.ERR_ScopedTypeNameDisallowed, "scoped").WithLocation(9, 20),
// (21,12): error CS9062: Types and aliases cannot be named 'scoped'.
// void M<scoped>() { } // 3
Diagnostic(ErrorCode.ERR_ScopedTypeNameDisallowed, "scoped").WithLocation(21, 12)
);
}
[Fact, WorkItem(62931, "https://github.com/dotnet/roslyn/issues/62931")]
public void ScopedReserved_Alias()
{
var source = """
using scoped = System.Int32;
""";
var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10);
comp.VerifyDiagnostics(
// (1,1): hidden CS8019: Unnecessary using directive.
// using scoped = System.Int32;
Diagnostic(ErrorCode.HDN_UnusedUsingDirective, "using scoped = System.Int32;").WithLocation(1, 1),
// (1,7): warning CS8981: The type name 'scoped' only contains lower-cased ascii characters. Such names may become reserved for the language.
// using scoped = System.Int32;
Diagnostic(ErrorCode.WRN_LowerCaseTypeName, "scoped").WithArguments("scoped").WithLocation(1, 7)
);
comp = CreateCompilation(source, parseOptions: TestOptions.Regular11);
comp.VerifyDiagnostics(
// (1,1): hidden CS8019: Unnecessary using directive.
// using scoped = System.Int32;
Diagnostic(ErrorCode.HDN_UnusedUsingDirective, "using scoped = System.Int32;").WithLocation(1, 1),
// (1,7): error CS9062: Types and aliases cannot be named 'scoped'.
// using scoped = System.Int32;
Diagnostic(ErrorCode.ERR_ScopedTypeNameDisallowed, "scoped").WithLocation(1, 7)
);
}
[Fact, WorkItem(62931, "https://github.com/dotnet/roslyn/issues/62931")]
public void ScopedReserved_Alias_Escaped()
{
var source = """
using @scoped = System.Int32;
""";
var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10);
comp.VerifyDiagnostics(
// (1,1): hidden CS8019: Unnecessary using directive.
// using @scoped = System.Int32;
Diagnostic(ErrorCode.HDN_UnusedUsingDirective, "using @scoped = System.Int32;").WithLocation(1, 1)
);
comp = CreateCompilation(source, parseOptions: TestOptions.Regular11);
comp.VerifyDiagnostics(
// (1,1): hidden CS8019: Unnecessary using directive.
// using @scoped = System.Int32;
Diagnostic(ErrorCode.HDN_UnusedUsingDirective, "using @scoped = System.Int32;").WithLocation(1, 1)
);
}
[Theory]
[InlineData("struct")]
[InlineData("ref struct")]
public void UnscopedRefAttribute_Method_01(string type)
{
var source =
$@"using System.Diagnostics.CodeAnalysis;
{type} S1
{{
private int _field;
public ref int GetField1() => ref _field; // 1
[UnscopedRef] public ref int GetField2() => ref _field;
}}";
var comp = CreateCompilation(new[] { source, UnscopedRefAttributeDefinition });
comp.VerifyDiagnostics(
// (5,39): error CS8170: Struct members cannot return 'this' or other instance members by reference
// public ref int GetField1() => ref _field; // 1
Diagnostic(ErrorCode.ERR_RefReturnStructThis, "_field").WithLocation(5, 39));
}
[Theory]
[InlineData("struct")]
[InlineData("ref struct")]
public void UnscopedRefAttribute_Method_02(string type)
{
var source =
$@"using System.Diagnostics.CodeAnalysis;
{type} S
{{
ref S F1()
{{
ref S s1 = ref this;
return ref s1;
}}
[UnscopedRef] ref S F2()
{{
ref S s2 = ref this;
return ref s2;
}}
}}";
var comp = CreateCompilation(new[] { source, UnscopedRefAttributeDefinition });
comp.VerifyDiagnostics(
// (7,20): error CS8157: Cannot return 's1' by reference because it was initialized to a value that cannot be returned by reference
// return ref s1;
Diagnostic(ErrorCode.ERR_RefReturnNonreturnableLocal, "s1").WithArguments("s1").WithLocation(7, 20));
}
[CombinatorialData]
[Theory]
public void UnscopedRefAttribute_Method_03(bool useCompilationReference)
{
var sourceA =
@"using System.Diagnostics.CodeAnalysis;
public struct S<T>
{
private T _t;
public ref T F1() => throw null;
[UnscopedRef] public ref T F2() => ref _t;
}";
var comp = CreateCompilation(new[] { sourceA, UnscopedRefAttributeDefinition });
comp.VerifyEmitDiagnostics();
var refA = AsReference(comp, useCompilationReference);
var sourceB =
@"class Program
{
static ref int F1()
{
var s = new S<int>();
return ref s.F1();
}
static ref int F2()
{
var s = new S<int>();
return ref s.F2(); // 1
}
}";
comp = CreateCompilation(sourceB, references: new[] { refA });
comp.VerifyEmitDiagnostics(
// (11,20): error CS8168: Cannot return local 's' by reference because it is not a ref local
// return ref s.F2(); // 1
Diagnostic(ErrorCode.ERR_RefReturnLocal, "s").WithArguments("s").WithLocation(11, 20));
}
[Theory]
[InlineData("struct")]
[InlineData("ref struct")]
public void UnscopedRefAttribute_Method_04(string type)
{
var source =
$@"using System.Diagnostics.CodeAnalysis;
ref struct R
{{
public R(ref S1 s1) {{ }}
public R(in S2 s2) {{ }}
}}
{type} S1
{{
void F1(ref R r1)
{{
r1 = new R(ref this); // 1
}}
[UnscopedRef] void F2(ref R r2)
{{
r2 = new R(ref this); // 2
}}
}}
readonly {type} S2
{{
void F3(ref R r3)
{{
r3 = new R(in this); // 3
}}
[UnscopedRef] void F4(ref R r4)
{{
r4 = new R(in this); // 4
}}
}}
";
var comp = CreateCompilation(new[] { source, UnscopedRefAttributeDefinition });
comp.VerifyDiagnostics(
// (11,14): error CS8347: Cannot use a result of 'R.R(ref S1)' in this context because it may expose variables referenced by parameter 's1' outside of their declaration scope
// r1 = new R(ref this); // 1
Diagnostic(ErrorCode.ERR_EscapeCall, "new R(ref this)").WithArguments("R.R(ref S1)", "s1").WithLocation(11, 14),
// (11,24): error CS8170: Struct members cannot return 'this' or other instance members by reference
// r1 = new R(ref this); // 1
Diagnostic(ErrorCode.ERR_RefReturnStructThis, "this").WithLocation(11, 24),
// (15,14): error CS8347: Cannot use a result of 'R.R(ref S1)' in this context because it may expose variables referenced by parameter 's1' outside of their declaration scope
// r2 = new R(ref this); // 2
Diagnostic(ErrorCode.ERR_EscapeCall, "new R(ref this)").WithArguments("R.R(ref S1)", "s1").WithLocation(15, 14),
// (15,24): error CS8170: Struct members cannot return 'this' or other instance members by reference
// r2 = new R(ref this); // 2
Diagnostic(ErrorCode.ERR_RefReturnStructThis, "this").WithLocation(15, 24),
// (22,14): error CS8347: Cannot use a result of 'R.R(in S2)' in this context because it may expose variables referenced by parameter 's2' outside of their declaration scope
// r3 = new R(in this); // 3
Diagnostic(ErrorCode.ERR_EscapeCall, "new R(in this)").WithArguments("R.R(in S2)", "s2").WithLocation(22, 14),
// (22,23): error CS8170: Struct members cannot return 'this' or other instance members by reference
// r3 = new R(in this); // 3
Diagnostic(ErrorCode.ERR_RefReturnStructThis, "this").WithLocation(22, 23),
// (26,14): error CS8347: Cannot use a result of 'R.R(in S2)' in this context because it may expose variables referenced by parameter 's2' outside of their declaration scope
// r4 = new R(in this); // 4
Diagnostic(ErrorCode.ERR_EscapeCall, "new R(in this)").WithArguments("R.R(in S2)", "s2").WithLocation(26, 14),
// (26,23): error CS8170: Struct members cannot return 'this' or other instance members by reference
// r4 = new R(in this); // 4
Diagnostic(ErrorCode.ERR_RefReturnStructThis, "this").WithLocation(26, 23));
}
[Fact]
public void UnscopedRefAttribute_Property_01()
{
var source =
@"using System.Diagnostics.CodeAnalysis;
struct S1
{
private int _field;
public ref int Property1 => ref _field; // 1
[UnscopedRef] public ref int Property2 => ref _field;
}";
var comp = CreateCompilation(new[] { source, UnscopedRefAttributeDefinition });
comp.VerifyDiagnostics(
// (5,37): error CS8170: Struct members cannot return 'this' or other instance members by reference
// public ref int Property1 => ref _field; // 1
Diagnostic(ErrorCode.ERR_RefReturnStructThis, "_field").WithLocation(5, 37));
}
[CombinatorialData]
[Theory]
public void UnscopedRefAttribute_Property_02(bool useCompilationReference)
{
var sourceA =
@"using System.Diagnostics.CodeAnalysis;
public struct S<T>
{
private T _t;
public ref T P1 => throw null;
[UnscopedRef] public ref T P2 => ref _t;
}";
var comp = CreateCompilation(new[] { sourceA, UnscopedRefAttributeDefinition });
comp.VerifyEmitDiagnostics();
var refA = AsReference(comp, useCompilationReference);
var sourceB =
@"class Program
{
static ref int F1()
{
var s = new S<int>();
return ref s.P1;
}
static ref int F2()
{
var s = new S<int>();
return ref s.P2; // 1
}
}";
comp = CreateCompilation(sourceB, references: new[] { refA });
comp.VerifyEmitDiagnostics(
// (11,20): error CS8168: Cannot return local 's' by reference because it is not a ref local
// return ref s.P2; // 1
Diagnostic(ErrorCode.ERR_RefReturnLocal, "s").WithArguments("s").WithLocation(11, 20));
}
[Fact]
public void UnscopedRefAttribute_Property_03()
{
var source =
@"using System.Diagnostics.CodeAnalysis;
struct S
{
[UnscopedRef] object P1 { get; }
[UnscopedRef] object P2 { get; set; }
[UnscopedRef] object P3 { get; init; } // 1
object P5
{
[UnscopedRef] get;
[UnscopedRef] set;
}
object P6
{
[UnscopedRef] get;
[UnscopedRef] init; // 2
}
}";
var comp = CreateCompilation(new[] { source, UnscopedRefAttributeDefinition, IsExternalInitTypeDefinition });
comp.VerifyDiagnostics(
// (6,6): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members.
// [UnscopedRef] object P3 { get; init; } // 1
Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(6, 6),
// (15,10): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members.
// [UnscopedRef] init; // 2
Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(15, 10));
}
[Theory]
[CombinatorialData]
public void UnscopedRefAttribute_Accessor_01(
[CombinatorialValues("struct", "ref struct")] string type,
[CombinatorialValues("ref", "ref readonly")] string refModifier)
{
var source =
$@"using System.Diagnostics.CodeAnalysis;
{type} S<T>
{{
private T _t;
{refModifier} T P1
{{
get => ref _t; // 1
}}
{refModifier} T P2
{{
[UnscopedRef]
get => ref _t;
}}
}}";
var comp = CreateCompilation(new[] { source, UnscopedRefAttributeDefinition });
comp.VerifyDiagnostics(
// (7,20): error CS8170: Struct members cannot return 'this' or other instance members by reference
// get => ref _t; // 1
Diagnostic(ErrorCode.ERR_RefReturnStructThis, "_t").WithLocation(7, 20));
}
[Fact]
public void UnscopedRefAttribute_Accessor_02()
{
var source =
@"using System.Diagnostics.CodeAnalysis;
ref struct R<T>
{
public ref T F;
}
struct A
{
R<A> this[int i]
{
get { return default; }
set { value.F = ref this; } // 1
}
}
struct B
{
R<B> this[int i]
{
get { return default; }
[UnscopedRef]
set { value.F = ref this; } // 2
}
}";
var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70);
comp.VerifyDiagnostics(
// (11,15): error CS8374: Cannot ref-assign 'this' to 'F' because 'this' has a narrower escape scope than 'F'.
// set { value.F = ref this; } // 1
Diagnostic(ErrorCode.ERR_RefAssignNarrower, "value.F = ref this").WithArguments("F", "this").WithLocation(11, 15),
// (20,15): error CS9079: Cannot ref-assign 'this' to 'F' because 'this' can only escape the current method through a return statement.
// set { value.F = ref this; } // 2
Diagnostic(ErrorCode.ERR_RefAssignReturnOnly, "value.F = ref this").WithArguments("F", "this").WithLocation(20, 15));
}
[Fact]
public void UnscopedRefAttribute_Accessor_03()
{
var source =
@"using System.Diagnostics.CodeAnalysis;
ref struct R<T>
{
public ref T F;
}
struct A
{
R<A> this[int i]
{
get { return default; }
init { value.F = ref this; } // 1
}
}
struct B
{
R<B> this[int i]
{
get { return default; }
[UnscopedRef]
init { value.F = ref this; } // 2
}
}";
var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70);
comp.VerifyDiagnostics(
// (11,16): error CS8374: Cannot ref-assign 'this' to 'F' because 'this' has a narrower escape scope than 'F'.
// init { value.F = ref this; } // 1
Diagnostic(ErrorCode.ERR_RefAssignNarrower, "value.F = ref this").WithArguments("F", "this").WithLocation(11, 16),
// (19,10): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members.
// [UnscopedRef]
Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(19, 10),
// (20,16): error CS8374: Cannot ref-assign 'this' to 'F' because 'this' has a narrower escape scope than 'F'.
// init { value.F = ref this; } // 2
Diagnostic(ErrorCode.ERR_RefAssignNarrower, "value.F = ref this").WithArguments("F", "this").WithLocation(20, 16));
}
[ConditionalFact(typeof(CoreClrOnly))]
public void UnscopedRefAttribute_Event_01()
{
var source =
@"#pragma warning disable 67
using System.Diagnostics.CodeAnalysis;
delegate void D();
class C
{
[UnscopedRef] event D E1; // 1
[UnscopedRef] event D E2 { add { } remove { } } // 2
}
struct S
{
[UnscopedRef] event D E3; // 3
[UnscopedRef] event D E4 { add { } remove { } } // 4
}
interface I
{
[UnscopedRef] event D E5; // 5
[UnscopedRef] event D E6 { add { } remove { } } // 6
}";
var comp = CreateCompilation(new[] { source, UnscopedRefAttributeDefinition }, targetFramework: TargetFramework.Net60);
comp.VerifyDiagnostics(
// (6,6): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members.
// [UnscopedRef] event D E1; // 1
Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(6, 6),
// (7,6): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members.
// [UnscopedRef] event D E2 { add { } remove { } } // 2
Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(7, 6),
// (11,6): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members.
// [UnscopedRef] event D E3; // 3
Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(11, 6),
// (12,6): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members.
// [UnscopedRef] event D E4 { add { } remove { } } // 4
Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(12, 6),
// (16,6): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members.
// [UnscopedRef] event D E5; // 5
Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(16, 6),
// (17,6): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members.
// [UnscopedRef] event D E6 { add { } remove { } } // 6
Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(17, 6));
}
[ConditionalFact(typeof(CoreClrOnly))]
public void UnscopedRefAttribute_Event_02()
{
var source =
@"#pragma warning disable 67
using System.Diagnostics.CodeAnalysis;
delegate void D();
class C
{
event D E1 { [UnscopedRef] add { } remove { } } // 1
event D E2 { add { } [UnscopedRef] remove { } } // 2
}
struct S
{
event D E3 { [UnscopedRef] add { } remove { } } // 3
event D E4 { add { } [UnscopedRef] remove { } } // 4
}
interface I
{
event D E5 { [UnscopedRef] add { } remove { } } // 5
event D E6 { add { } [UnscopedRef] remove { } } // 6
}
";
var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70);
comp.VerifyDiagnostics(
// (6,19): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members.
// event D E1 { [UnscopedRef] add { } remove { } } // 1
Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(6, 19),
// (7,27): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members.
// event D E2 { add { } [UnscopedRef] remove { } } // 2
Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(7, 27),
// (11,19): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members.
// event D E3 { [UnscopedRef] add { } remove { } } // 3
Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(11, 19),
// (12,27): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members.
// event D E4 { add { } [UnscopedRef] remove { } } // 4
Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(12, 27),
// (16,19): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members.
// event D E5 { [UnscopedRef] add { } remove { } } // 5
Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(16, 19),
// (17,27): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members.
// event D E6 { add { } [UnscopedRef] remove { } } // 6
Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(17, 27));
}
[Theory]
[InlineData("class")]
[InlineData("struct")]
[InlineData("ref struct")]
public void UnscopedRefAttribute_Method_05(string type)
{
var source =
$@"using System.Diagnostics.CodeAnalysis;
{type} C
{{
void F()
{{
var d = [UnscopedRef] (ref int i) => ref i;
[UnscopedRef] ref int Local() => throw null;
Local();
}}
}}
";
var comp = CreateCompilation(new[] { source, UnscopedRefAttributeDefinition });
comp.VerifyDiagnostics(
// (6,18): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members.
// var d = [UnscopedRef] (ref int i) => ref i;
Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(6, 18),
// (7,10): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members.
// [UnscopedRef] ref int Local() => throw null;
Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(7, 10));
}
[Theory]
[CombinatorialData]
public void UnscopedRefAttribute_SubstitutedMembers(bool useCompilationReference)
{
var sourceA =
@"using System.Diagnostics.CodeAnalysis;
public ref struct R1<T>
{
private T _t;
public R1(T t) { _t = t; }
public ref T Get() => ref this[0];
public ref T this[int index] => throw null;
}
public ref struct R2<T>
{
private T _t;
public R2(T t) { _t = t; }
[UnscopedRef] public ref T Get() => ref this[0];
[UnscopedRef] public ref T this[int index] => ref _t;
}";
var comp = CreateCompilation(new[] { sourceA, UnscopedRefAttributeDefinition });
comp.VerifyEmitDiagnostics();
var refA = AsReference(comp, useCompilationReference);
var sourceB =
@"class Program
{
static ref int F1(bool b)
{
R1<int> r1 = new R1<int>(1);
if (b) return ref r1.Get();
return ref r1[0];
}
static ref int F2(bool b)
{
R2<int> r2 = new R2<int>(2);
if (b) return ref r2.Get(); // 1
return ref r2[0]; // 2
}
}";
comp = CreateCompilation(sourceB, references: new[] { refA });
comp.VerifyDiagnostics(
// (12,27): error CS8168: Cannot return local 'r2' by reference because it is not a ref local
// if (b) return ref r2.Get(); // 1
Diagnostic(ErrorCode.ERR_RefReturnLocal, "r2").WithArguments("r2").WithLocation(12, 27),
// (13,20): error CS8168: Cannot return local 'r2' by reference because it is not a ref local
// return ref r2[0]; // 2
Diagnostic(ErrorCode.ERR_RefReturnLocal, "r2").WithArguments("r2").WithLocation(13, 20));
var tree = comp.SyntaxTrees[0];
var model = comp.GetSemanticModel(tree);
var decls = tree.GetRoot().DescendantNodes().OfType<VariableDeclaratorSyntax>().Where(v => v.Identifier.Text is "r1" or "r2").ToArray();
var types = decls.Select(d => (NamedTypeSymbol)model.GetDeclaredSymbol(d).GetSymbol<LocalSymbol>().Type).ToArray();
var type = types[0];
Assert.Equal("R1<System.Int32>", type.ToTestDisplayString());
VerifyParameterSymbol(type.GetMethod("Get").ThisParameter, "ref R1<System.Int32> this", RefKind.Ref, ScopedKind.ScopedRef, expectedHasUnscopedRefAttribute: false);
VerifyParameterSymbol(type.GetMethod("get_Item").ThisParameter, "ref R1<System.Int32> this", RefKind.Ref, ScopedKind.ScopedRef, expectedHasUnscopedRefAttribute: false);
type = types[1];
Assert.Equal("R2<System.Int32>", type.ToTestDisplayString());
VerifyParameterSymbol(type.GetMethod("Get").ThisParameter, "ref R2<System.Int32> this", RefKind.Ref, ScopedKind.None, expectedHasUnscopedRefAttribute: true);
VerifyParameterSymbol(type.GetMethod("get_Item").ThisParameter, "ref R2<System.Int32> this", RefKind.Ref, ScopedKind.None, expectedHasUnscopedRefAttribute: true);
}
[Fact]
public void UnscopedRefAttribute_RetargetingMembers()
{
var sourceA =
@"using System.Diagnostics.CodeAnalysis;
public ref struct R1<T>
{
private readonly T _t;
public R1(T t) { _t = t; }
public ref readonly T Get() => ref this[0];
public ref readonly T this[int index] => ref _t; // 1
}
public ref struct R2<T>
{
private readonly T _t;
public R2(T t) { _t = t; }
[UnscopedRef] public ref readonly T Get() => ref this[0];
[UnscopedRef] public ref readonly T this[int index] => ref _t;
}";
var comp = CreateCompilation(new[] { sourceA, UnscopedRefAttributeDefinition }, targetFramework: TargetFramework.Mscorlib40);
comp.VerifyDiagnostics(
// (7,50): error CS8170: Struct members cannot return 'this' or other instance members by reference
// public ref readonly T this[int index] => ref _t; // 1
Diagnostic(ErrorCode.ERR_RefReturnStructThis, "_t").WithLocation(7, 50));
var refA = comp.ToMetadataReference();
var sourceB =
@"class Program
{
static ref readonly int F1(bool b)
{
R1<int> r1 = new R1<int>(1);
if (b) return ref r1.Get();
return ref r1[0];
}
static ref readonly int F2(bool b)
{
R2<int> r2 = new R2<int>(2);
if (b) return ref r2.Get(); // 1
return ref r2[0]; // 2
}
}";
comp = CreateCompilation(sourceB, new[] { refA }, targetFramework: TargetFramework.Mscorlib45);
comp.VerifyEmitDiagnostics(
// (12,27): error CS8168: Cannot return local 'r2' by reference because it is not a ref local
// if (b) return ref r2.Get(); // 1
Diagnostic(ErrorCode.ERR_RefReturnLocal, "r2").WithArguments("r2").WithLocation(12, 27),
// (13,20): error CS8168: Cannot return local 'r2' by reference because it is not a ref local
// return ref r2[0]; // 2
Diagnostic(ErrorCode.ERR_RefReturnLocal, "r2").WithArguments("r2").WithLocation(13, 20));
var tree = comp.SyntaxTrees[0];
var model = comp.GetSemanticModel(tree);
var decls = tree.GetRoot().DescendantNodes().OfType<VariableDeclaratorSyntax>().Where(v => v.Identifier.Text is "r1" or "r2").ToArray();
var types = decls.Select(d => (NamedTypeSymbol)model.GetDeclaredSymbol(d).GetSymbol<LocalSymbol>().Type).ToArray();
var type = types[0];
var underlyingType = (RetargetingNamedTypeSymbol)type.OriginalDefinition;
Assert.Equal("R1<System.Int32>", type.ToTestDisplayString());
VerifyParameterSymbol(type.GetMethod("Get").ThisParameter, "ref R1<System.Int32> this", RefKind.Ref, ScopedKind.ScopedRef, expectedHasUnscopedRefAttribute: false);
VerifyParameterSymbol(type.GetMethod("get_Item").ThisParameter, "ref R1<System.Int32> this", RefKind.Ref, ScopedKind.ScopedRef, expectedHasUnscopedRefAttribute: false);
type = types[1];
underlyingType = (RetargetingNamedTypeSymbol)type.OriginalDefinition;
Assert.Equal("R2<System.Int32>", type.ToTestDisplayString());
VerifyParameterSymbol(type.GetMethod("Get").ThisParameter, "ref R2<System.Int32> this", RefKind.Ref, ScopedKind.None, expectedHasUnscopedRefAttribute: true);
VerifyParameterSymbol(type.GetMethod("get_Item").ThisParameter, "ref R2<System.Int32> this", RefKind.Ref, ScopedKind.None, expectedHasUnscopedRefAttribute: true);
}
[Fact]
public void UnscopedRefAttribute_Constructor()
{
var source =
@"using System.Diagnostics.CodeAnalysis;
ref struct R<T>
{
public ref T F;
}
struct A
{
A(R<A> r)
{
r.F = ref this; // 1
}
}
struct B
{
[UnscopedRef]
B(R<B> r)
{
r.F = ref this; // 2
}
}";
var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70);
comp.VerifyDiagnostics(
// (10,9): error CS8374: Cannot ref-assign 'this' to 'F' because 'this' has a narrower escape scope than 'F'.
// r.F = ref this; // 1
Diagnostic(ErrorCode.ERR_RefAssignNarrower, "r.F = ref this").WithArguments("F", "this").WithLocation(10, 9),
// (15,6): error CS0592: Attribute 'UnscopedRef' is not valid on this declaration type. It is only valid on 'method, property, indexer, parameter' declarations.
// [UnscopedRef]
Diagnostic(ErrorCode.ERR_AttributeOnBadSymbolType, "UnscopedRef").WithArguments("UnscopedRef", "method, property, indexer, parameter").WithLocation(15, 6),
// (18,9): error CS8374: Cannot ref-assign 'this' to 'F' because 'this' has a narrower escape scope than 'F'.
// r.F = ref this; // 2
Diagnostic(ErrorCode.ERR_RefAssignNarrower, "r.F = ref this").WithArguments("F", "this").WithLocation(18, 9));
// With UnscopedRefAttribute definition that allows use on constructors.
comp = CreateCompilation(new[] { source, UnscopedRefAttributeDefinition }, targetFramework: TargetFramework.Net70);
comp.VerifyDiagnostics(
// (10,9): error CS8374: Cannot ref-assign 'this' to 'F' because 'this' has a narrower escape scope than 'F'.
// r.F = ref this; // 1
Diagnostic(ErrorCode.ERR_RefAssignNarrower, "r.F = ref this").WithArguments("F", "this").WithLocation(10, 9),
// (15,6): warning CS0436: The type 'UnscopedRefAttribute' in '1.cs' conflicts with the imported type 'UnscopedRefAttribute' in 'System.Runtime, Version=7.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'. Using the type defined in ''.
// [UnscopedRef]
Diagnostic(ErrorCode.WRN_SameFullNameThisAggAgg, "UnscopedRef").WithArguments("1.cs", "System.Diagnostics.CodeAnalysis.UnscopedRefAttribute", "System.Runtime, Version=7.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", "System.Diagnostics.CodeAnalysis.UnscopedRefAttribute").WithLocation(15, 6),
// (15,6): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members.
// [UnscopedRef]
Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(15, 6),
// (18,9): error CS8374: Cannot ref-assign 'this' to 'F' because 'this' has a narrower escape scope than 'F'.
// r.F = ref this; // 2
Diagnostic(ErrorCode.ERR_RefAssignNarrower, "r.F = ref this").WithArguments("F", "this").WithLocation(18, 9));
}
[Fact]
public void UnscopedRefAttribute_Destructor()
{
var source =
@"using System.Diagnostics.CodeAnalysis;
class C
{
[UnscopedRef] ~C() { }
}";
var comp = CreateCompilation(new[] { source, UnscopedRefAttributeDefinition });
comp.VerifyDiagnostics(
// (4,6): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members.
// [UnscopedRef] ~C() { }
Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(4, 6));
}
[Fact]
public void UnscopedRefAttribute_StaticMembers()
{
var source =
@"using System.Diagnostics.CodeAnalysis;
struct S
{
[UnscopedRef] static S() { } // 1
[UnscopedRef] static object F() => null; // 2
[UnscopedRef] static object P => null; // 3
}";
var comp = CreateCompilation(new[] { source, UnscopedRefAttributeDefinition });
comp.VerifyDiagnostics(
// (4,6): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members.
// [UnscopedRef] static S() { } // 1
Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(4, 6),
// (5,6): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members.
// [UnscopedRef] static object F() => null; // 2
Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(5, 6),
// (6,6): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members.
// [UnscopedRef] static object P => null; // 3
Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(6, 6));
}
[Fact]
public void UnscopedRefAttribute_OtherTypes()
{
var source =
@"using System.Diagnostics.CodeAnalysis;
class C
{
[UnscopedRef] object F1() => null; // 1
}
record R
{
[UnscopedRef] object F2() => null; // 2
}
record struct S
{
[UnscopedRef] object F3() => null;
}";
var comp = CreateCompilation(new[] { source, UnscopedRefAttributeDefinition });
comp.VerifyDiagnostics(
// (4,6): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members.
// [UnscopedRef] object F1() => null; // 1
Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(4, 6),
// (8,6): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members.
// [UnscopedRef] object F2() => null; // 2
Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(8, 6));
}
[WorkItem(62691, "https://github.com/dotnet/roslyn/issues/62691")]
[Fact]
public void UnscopedRefAttribute_RefRefStructParameter_01()
{
var source =
@"
ref struct R { }
class Program
{
static ref R ReturnRefStructRef(bool b, scoped ref R x, ref R y)
{
if (b)
return ref x; // 1
else
return ref y;
}
}";
var comp = CreateCompilation(source);
comp.VerifyDiagnostics(
// (8,24): error CS9075: Cannot return a parameter by reference 'x' because it is scoped to the current method
// return ref x; // 1
Diagnostic(ErrorCode.ERR_RefReturnScopedParameter, "x").WithArguments("x").WithLocation(8, 24));
var parameters = comp.GetMember<MethodSymbol>("Program.ReturnRefStructRef").Parameters;
VerifyParameterSymbol(parameters[1], "scoped ref R x", RefKind.Ref, ScopedKind.ScopedRef);
VerifyParameterSymbol(parameters[2], "ref R y", RefKind.Ref, ScopedKind.None);
}
[CombinatorialData]
[Theory, WorkItem(63070, "https://github.com/dotnet/roslyn/issues/63070")]
public void UnscopedRefAttribute_RefRefStructParameter_02(bool useCompilationReference)
{
var sourceA =
@"
public ref struct R<T>
{
public ref T F;
public R(ref T t) { F = ref t; }
}
public class A<T>
{
public ref T F1A(ref R<T> r1)
{
return ref r1.F;
}
public ref T F2A(scoped ref R<T> r2)
{
return ref r2.F;
}
}";
var comp = CreateCompilation(sourceA, targetFramework: TargetFramework.Net70);
comp.VerifyEmitDiagnostics();
var refA = AsReference(comp, useCompilationReference);
var sourceB1 =
@"class B1 : A<int>
{
ref int F1B()
{
int i = 1;
var r = new R<int>(ref i);
return ref F1A(ref r); // 1
}
ref int F2B()
{
int i = 2;
var r = new R<int>(ref i);
return ref F2A(ref r); // 2
}
}";
comp = CreateCompilation(sourceB1, references: new[] { refA }, targetFramework: TargetFramework.Net70);
comp.VerifyEmitDiagnostics(
// (7,20): error CS8347: Cannot use a result of 'A<int>.F1A(ref R<int>)' in this context because it may expose variables referenced by parameter 'r1' outside of their declaration scope
// return ref F1A(ref r); // 1
Diagnostic(ErrorCode.ERR_EscapeCall, "F1A(ref r)").WithArguments("A<int>.F1A(ref R<int>)", "r1").WithLocation(7, 20),
// (7,28): error CS8352: Cannot use variable 'r' in this context because it may expose referenced variables outside of their declaration scope
// return ref F1A(ref r); // 1
Diagnostic(ErrorCode.ERR_EscapeVariable, "r").WithArguments("r").WithLocation(7, 28),
// (13,20): error CS8347: Cannot use a result of 'A<int>.F2A(scoped ref R<int>)' in this context because it may expose variables referenced by parameter 'r2' outside of their declaration scope
// return ref F2A(ref r); // 2
Diagnostic(ErrorCode.ERR_EscapeCall, "F2A(ref r)").WithArguments("A<int>.F2A(scoped ref R<int>)", "r2").WithLocation(13, 20),
// (13,28): error CS8352: Cannot use variable 'r' in this context because it may expose referenced variables outside of their declaration scope
// return ref F2A(ref r); // 2
Diagnostic(ErrorCode.ERR_EscapeVariable, "r").WithArguments("r").WithLocation(13, 28)
);
var baseType = comp.GetMember<NamedTypeSymbol>("B1").BaseTypeNoUseSiteDiagnostics;
VerifyParameterSymbol(baseType.GetMethod("F1A").Parameters[0], "ref R<System.Int32> r1", RefKind.Ref, ScopedKind.None);
VerifyParameterSymbol(baseType.GetMethod("F2A").Parameters[0], "scoped ref R<System.Int32> r2", RefKind.Ref, ScopedKind.ScopedRef);
var sourceB2 =
@"class B2 : A<int>
{
ref int F1B(ref int i)
{
var r = new R<int>(ref i);
return ref F1A(ref r); // 1, 2
}
ref int F2B(ref int i)
{
var r = new R<int>(ref i);
return ref F2A(ref r);
}
ref int F1C(ref int i)
{
var r = new R<int>(ref i);
ref var y = ref F1A(ref r);
return ref y; // 3
}
ref int F2C(ref int i)
{
var r = new R<int>(ref i);
ref var y = ref F2A(ref r);
return ref y;
}
}";
comp = CreateCompilation(sourceB2, references: new[] { refA }, targetFramework: TargetFramework.Net70);
comp.VerifyEmitDiagnostics(
// (6,20): error CS8347: Cannot use a result of 'A<int>.F1A(ref R<int>)' in this context because it may expose variables referenced by parameter 'r1' outside of their declaration scope
// return ref F1A(ref r); // 1, 2
Diagnostic(ErrorCode.ERR_EscapeCall, "F1A(ref r)").WithArguments("A<int>.F1A(ref R<int>)", "r1").WithLocation(6, 20),
// (6,28): error CS8168: Cannot return local 'r' by reference because it is not a ref local
// return ref F1A(ref r); // 1, 2
Diagnostic(ErrorCode.ERR_RefReturnLocal, "r").WithArguments("r").WithLocation(6, 28),
// (18,20): error CS8157: Cannot return 'y' by reference because it was initialized to a value that cannot be returned by reference
// return ref y; // 3
Diagnostic(ErrorCode.ERR_RefReturnNonreturnableLocal, "y").WithArguments("y").WithLocation(18, 20));
}
[Fact, WorkItem(63057, "https://github.com/dotnet/roslyn/issues/63057")]
public void UnscopedScoped_Source()
{
var sourceA =
@"using System.Diagnostics.CodeAnalysis;
public ref struct R<T>
{
public ref T F;
public R(ref T t) { F = ref t; }
}
public class A<T>
{
public ref T F1([UnscopedRef] scoped ref R<T> r1) // 1
{
return ref r1.F;
}
public ref T F2([UnscopedRef] scoped out T t2) // 2
{
t2 = default;
return ref t2;
}
public ref T F3([UnscopedRef] scoped in R<T> t3) // 3
{
throw null;
}
public ref T F4([UnscopedRef] scoped R<T> t4) // 4
{
throw null;
}
}";
var comp = CreateCompilation(sourceA, targetFramework: TargetFramework.Net70);
comp.VerifyEmitDiagnostics(
// (9,22): error CS9066: UnscopedRefAttribute cannot be applied to parameters that have a 'scoped' modifier.
// public ref T F1([UnscopedRef] scoped ref R<T> r1) // 1
Diagnostic(ErrorCode.ERR_UnscopedScoped, "UnscopedRef").WithLocation(9, 22),
// (13,22): error CS9066: UnscopedRefAttribute cannot be applied to parameters that have a 'scoped' modifier.
// public ref T F2([UnscopedRef] scoped out T t2) // 2
Diagnostic(ErrorCode.ERR_UnscopedScoped, "UnscopedRef").WithLocation(13, 22),
// (18,22): error CS9066: UnscopedRefAttribute cannot be applied to parameters that have a 'scoped' modifier.
// public ref T F3([UnscopedRef] scoped in R<T> t3) // 3
Diagnostic(ErrorCode.ERR_UnscopedScoped, "UnscopedRef").WithLocation(18, 22),
// (22,22): error CS9063: UnscopedRefAttribute cannot be applied to this parameter because it is unscoped by default.
// public ref T F4([UnscopedRef] scoped R<T> t4) // 4
Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedTarget, "UnscopedRef").WithLocation(22, 22));
var type = comp.GetMember<NamedTypeSymbol>("A");
VerifyParameterSymbol(type.GetMethod("F1").Parameters[0], "ref R<T> r1", RefKind.Ref, ScopedKind.None, expectedHasUnscopedRefAttribute: true);
VerifyParameterSymbol(type.GetMethod("F2").Parameters[0], "out T t2", RefKind.Out, ScopedKind.None, expectedHasUnscopedRefAttribute: true);
VerifyParameterSymbol(type.GetMethod("F3").Parameters[0], "in R<T> t3", RefKind.In, ScopedKind.None, expectedHasUnscopedRefAttribute: true);
VerifyParameterSymbol(type.GetMethod("F4").Parameters[0], "R<T> t4", RefKind.None, ScopedKind.None, expectedHasUnscopedRefAttribute: true);
}
[Fact, WorkItem(63070, "https://github.com/dotnet/roslyn/issues/63070")]
public void UnscopedScoped_Metadata()
{
// Equivalent to:
// public class A<T>
// {
// public ref T F4([UnscopedRef] scoped R<T> t4) { throw null; }
// }
var ilSource = """
.class public sequential ansi sealed beforefieldinit R`1<T>
extends [mscorlib]System.ValueType
{
.method public hidebysig specialname rtspecialname instance void .ctor ( !T& t ) cil managed
{
IL_0000: ldnull
IL_0001: throw
}
}
.class public auto ansi beforefieldinit A`1<T>
extends [mscorlib]System.Object
{
// [UnscopedRef] scoped parameter
.method public hidebysig instance !T& F4A ( valuetype R`1<!T>& r4 ) cil managed
{
.param [1]
.custom instance void System.Runtime.CompilerServices.ScopedRefAttribute::.ctor() = ( 01 00 00 00 )
.custom instance void System.Diagnostics.CodeAnalysis.UnscopedRefAttribute::.ctor() = ( 01 00 00 00 )
IL_0000: ldnull
IL_0001: throw
}
.method public hidebysig specialname rtspecialname instance void .ctor () cil managed
{
IL_0000: ldnull
IL_0001: throw
}
}
.class private auto ansi sealed beforefieldinit System.Runtime.CompilerServices.ScopedRefAttribute
extends [mscorlib]System.Attribute
{
.method public hidebysig specialname rtspecialname instance void .ctor () cil managed
{
IL_0000: ldnull
IL_0001: throw
}
}
.class public auto ansi sealed beforefieldinit System.Diagnostics.CodeAnalysis.UnscopedRefAttribute
extends [mscorlib]System.Attribute
{
.method public hidebysig specialname rtspecialname
instance void .ctor () cil managed
{
IL_0000: ldnull
IL_0001: throw
}
}
""";
var refA = CompileIL(ilSource);
var sourceB =
@"class B : A<int>
{
ref int F4B()
{
int i = 4;
var r = new R<int>(ref i);
return ref F4A(ref r); // 1
}
}";
var comp = CreateCompilation(sourceB, references: new[] { refA });
comp.VerifyEmitDiagnostics(
// (7,20): error CS0570: 'A<T>.F4A(ref R<T>)' is not supported by the language
// return ref F4A(ref r); // 1
Diagnostic(ErrorCode.ERR_BindToBogus, "F4A").WithArguments("A<T>.F4A(ref R<T>)").WithLocation(7, 20));
var baseType = comp.GetMember<NamedTypeSymbol>("B").BaseTypeNoUseSiteDiagnostics;
VerifyParameterSymbol(baseType.GetMethod("F4A").Parameters[0], "ref R<System.Int32> r4", RefKind.Ref, ScopedKind.None, expectedHasUnscopedRefAttribute: true);
}
[Fact]
public void UnscopedRefAttribute_Parameter_01()
{
var source =
@"using System.Diagnostics.CodeAnalysis;
class Program
{
static void F([UnscopedRef] int x, [UnscopedRef] object y) { }
}
";
var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70);
comp.VerifyDiagnostics(
// (4,20): error CS9063: UnscopedRefAttribute cannot be applied to this parameter because it is unscoped by default.
// static void F([UnscopedRef] int x, [UnscopedRef] object y) { }
Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedTarget, "UnscopedRef").WithLocation(4, 20),
// (4,41): error CS9063: UnscopedRefAttribute cannot be applied to this parameter because it is unscoped by default.
// static void F([UnscopedRef] int x, [UnscopedRef] object y) { }
Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedTarget, "UnscopedRef").WithLocation(4, 41));
var parameters = comp.GetMember<MethodSymbol>("Program.F").Parameters;
VerifyParameterSymbol(parameters[0], "System.Int32 x", RefKind.None, default, expectedHasUnscopedRefAttribute: true);
VerifyParameterSymbol(parameters[1], "System.Object y", RefKind.None, default, expectedHasUnscopedRefAttribute: true);
}
[Fact]
public void UnscopedRefAttribute_OutParameter_01()
{
var source =
@"using System.Diagnostics.CodeAnalysis;
class Program
{
static ref int ReturnOut(bool b, out int x, [UnscopedRef] out int y)
{
x = 1;
y = 2;
if (b)
return ref x; // 1
else
return ref y;
}
}";
var comp = CreateCompilation(new[] { source, UnscopedRefAttributeDefinition });
comp.VerifyDiagnostics(
// (9,24): error CS9075: Cannot return a parameter by reference 'x' because it is scoped to the current method
// return ref x; // 1
Diagnostic(ErrorCode.ERR_RefReturnScopedParameter, "x").WithArguments("x").WithLocation(9, 24));
var parameters = comp.GetMember<MethodSymbol>("Program.ReturnOut").Parameters;
VerifyParameterSymbol(parameters[1], "out System.Int32 x", RefKind.Out, ScopedKind.ScopedRef, expectedHasUnscopedRefAttribute: false);
VerifyParameterSymbol(parameters[2], "out System.Int32 y", RefKind.Out, ScopedKind.None, expectedHasUnscopedRefAttribute: true);
}
[CombinatorialData]
[Theory]
public void UnscopedRefAttribute_OutParameter_02(bool useCompilationReference)
{
var sourceA =
@"using System.Diagnostics.CodeAnalysis;
public class A<T>
{
public ref T F1A(out T t1)
{
throw null;
}
public ref T F2A(scoped out T t2)
{
throw null;
}
public ref T F3A([UnscopedRef] out T t3)
{
t3 = default;
return ref t3;
}
}";
var comp = CreateCompilation(new[] { sourceA, UnscopedRefAttributeDefinition });
comp.VerifyEmitDiagnostics();
var refA = AsReference(comp, useCompilationReference);
var sourceB =
@"class B : A<int>
{
ref int F1B()
{
int i = 1;
return ref F1A(out i);
}
ref int F2B()
{
int i = 2;
return ref F2A(out i);
}
ref int F3B()
{
int i = 3;
return ref F3A(out i); // 1
}
}";
comp = CreateCompilation(sourceB, references: new[] { refA });
comp.VerifyEmitDiagnostics(
// (16,20): error CS8347: Cannot use a result of 'A<int>.F3A(out int)' in this context because it may expose variables referenced by parameter 't3' outside of their declaration scope
// return ref F3A(out i); // 1
Diagnostic(ErrorCode.ERR_EscapeCall, "F3A(out i)").WithArguments("A<int>.F3A(out int)", "t3").WithLocation(16, 20),
// (16,28): error CS8168: Cannot return local 'i' by reference because it is not a ref local
// return ref F3A(out i); // 1
Diagnostic(ErrorCode.ERR_RefReturnLocal, "i").WithArguments("i").WithLocation(16, 28));
var baseType = comp.GetMember<NamedTypeSymbol>("B").BaseTypeNoUseSiteDiagnostics;
VerifyParameterSymbol(baseType.GetMethod("F1A").Parameters[0], "out System.Int32 t1", RefKind.Out, ScopedKind.ScopedRef, expectedHasUnscopedRefAttribute: false);
VerifyParameterSymbol(baseType.GetMethod("F2A").Parameters[0], "out System.Int32 t2", RefKind.Out, ScopedKind.ScopedRef, expectedHasUnscopedRefAttribute: false);
VerifyParameterSymbol(baseType.GetMethod("F3A").Parameters[0], "out System.Int32 t3", RefKind.Out, ScopedKind.None, expectedHasUnscopedRefAttribute: true);
}
[Fact]
public void UnscopedRefAttribute_RefParameter()
{
var source =
@"using System.Diagnostics.CodeAnalysis;
public class A<T>
{
public ref T F1A(ref T t1) => ref t1;
public ref T F2A(scoped ref T t2) => throw null;
public ref T F3A([UnscopedRef] ref T t3) => ref t3;
public ref T F4A([UnscopedRef] scoped ref T t4) => ref t4;
}
class B : A<int>
{
ref int F1B()
{
int i = 1;
return ref F1A(ref i); // 1
}
ref int F2B()
{
int i = 2;
return ref F2A(ref i);
}
ref int F3B()
{
int i = 3;
return ref F3A(ref i); // 2
}
ref int F4B()
{
int i = 4;
return ref F4A(ref i); // 3
}
}";
var comp = CreateCompilation(new[] { source, UnscopedRefAttributeDefinition });
comp.VerifyEmitDiagnostics(
// (7,23): error CS9066: UnscopedRefAttribute cannot be applied to parameters that have a 'scoped' modifier.
// public ref T F4A([UnscopedRef] scoped ref T t4) => ref t4;
Diagnostic(ErrorCode.ERR_UnscopedScoped, "UnscopedRef").WithLocation(7, 23),
// (14,20): error CS8347: Cannot use a result of 'A<int>.F1A(ref int)' in this context because it may expose variables referenced by parameter 't1' outside of their declaration scope
// return ref F1A(ref i); // 1
Diagnostic(ErrorCode.ERR_EscapeCall, "F1A(ref i)").WithArguments("A<int>.F1A(ref int)", "t1").WithLocation(14, 20),
// (14,28): error CS8168: Cannot return local 'i' by reference because it is not a ref local
// return ref F1A(ref i); // 1
Diagnostic(ErrorCode.ERR_RefReturnLocal, "i").WithArguments("i").WithLocation(14, 28),
// (24,20): error CS8347: Cannot use a result of 'A<int>.F3A(ref int)' in this context because it may expose variables referenced by parameter 't3' outside of their declaration scope
// return ref F3A(ref i); // 2
Diagnostic(ErrorCode.ERR_EscapeCall, "F3A(ref i)").WithArguments("A<int>.F3A(ref int)", "t3").WithLocation(24, 20),
// (24,28): error CS8168: Cannot return local 'i' by reference because it is not a ref local
// return ref F3A(ref i); // 2
Diagnostic(ErrorCode.ERR_RefReturnLocal, "i").WithArguments("i").WithLocation(24, 28),
// (29,20): error CS8347: Cannot use a result of 'A<int>.F4A(ref int)' in this context because it may expose variables referenced by parameter 't4' outside of their declaration scope
// return ref F4A(ref i); // 3
Diagnostic(ErrorCode.ERR_EscapeCall, "F4A(ref i)").WithArguments("A<int>.F4A(ref int)", "t4").WithLocation(29, 20),
// (29,28): error CS8168: Cannot return local 'i' by reference because it is not a ref local
// return ref F4A(ref i); // 3
Diagnostic(ErrorCode.ERR_RefReturnLocal, "i").WithArguments("i").WithLocation(29, 28));
var baseType = comp.GetMember<NamedTypeSymbol>("B").BaseTypeNoUseSiteDiagnostics;
VerifyParameterSymbol(baseType.GetMethod("F1A").Parameters[0], "ref System.Int32 t1", RefKind.Ref, ScopedKind.None, expectedHasUnscopedRefAttribute: false);
VerifyParameterSymbol(baseType.GetMethod("F2A").Parameters[0], "scoped ref System.Int32 t2", RefKind.Ref, ScopedKind.ScopedRef, expectedHasUnscopedRefAttribute: false);
VerifyParameterSymbol(baseType.GetMethod("F3A").Parameters[0], "ref System.Int32 t3", RefKind.Ref, ScopedKind.None, expectedHasUnscopedRefAttribute: true);
VerifyParameterSymbol(baseType.GetMethod("F4A").Parameters[0], "ref System.Int32 t4", RefKind.Ref, ScopedKind.None, expectedHasUnscopedRefAttribute: true);
}
[Fact]
public void UnscopedRefAttribute_InParameter()
{
var source =
@"using System.Diagnostics.CodeAnalysis;
public class A<T>
{
public ref readonly T F1A(in T t1) => ref t1;
public ref readonly T F2A(scoped in T t2) => throw null;
public ref readonly T F3A([UnscopedRef] in T t3) => ref t3;
public ref readonly T F4A([UnscopedRef] scoped in T t4) => ref t4;
}
class B : A<int>
{
ref readonly int F1B()
{
int i = 1;
return ref F1A(in i); // 1
}
ref readonly int F2B()
{
int i = 2;
return ref F2A(in i);
}
ref readonly int F3B()
{
int i = 3;
return ref F3A(in i); // 2
}
ref readonly int F4B()
{
int i = 4;
return ref F4A(in i); // 3
}
}";
var comp = CreateCompilation(new[] { source, UnscopedRefAttributeDefinition });
comp.VerifyEmitDiagnostics(
// (7,32): error CS9066: UnscopedRefAttribute cannot be applied to parameters that have a 'scoped' modifier.
// public ref readonly T F4A([UnscopedRef] scoped in T t4) => ref t4;
Diagnostic(ErrorCode.ERR_UnscopedScoped, "UnscopedRef").WithLocation(7, 32),
// (14,20): error CS8347: Cannot use a result of 'A<int>.F1A(in int)' in this context because it may expose variables referenced by parameter 't1' outside of their declaration scope
// return ref F1A(in i); // 1
Diagnostic(ErrorCode.ERR_EscapeCall, "F1A(in i)").WithArguments("A<int>.F1A(in int)", "t1").WithLocation(14, 20),
// (14,27): error CS8168: Cannot return local 'i' by reference because it is not a ref local
// return ref F1A(in i); // 1
Diagnostic(ErrorCode.ERR_RefReturnLocal, "i").WithArguments("i").WithLocation(14, 27),
// (24,20): error CS8347: Cannot use a result of 'A<int>.F3A(in int)' in this context because it may expose variables referenced by parameter 't3' outside of their declaration scope
// return ref F3A(in i); // 2
Diagnostic(ErrorCode.ERR_EscapeCall, "F3A(in i)").WithArguments("A<int>.F3A(in int)", "t3").WithLocation(24, 20),
// (24,27): error CS8168: Cannot return local 'i' by reference because it is not a ref local
// return ref F3A(in i); // 2
Diagnostic(ErrorCode.ERR_RefReturnLocal, "i").WithArguments("i").WithLocation(24, 27),
// (29,20): error CS8347: Cannot use a result of 'A<int>.F4A(in int)' in this context because it may expose variables referenced by parameter 't4' outside of their declaration scope
// return ref F4A(in i); // 3
Diagnostic(ErrorCode.ERR_EscapeCall, "F4A(in i)").WithArguments("A<int>.F4A(in int)", "t4").WithLocation(29, 20),
// (29,27): error CS8168: Cannot return local 'i' by reference because it is not a ref local
// return ref F4A(in i); // 3
Diagnostic(ErrorCode.ERR_RefReturnLocal, "i").WithArguments("i").WithLocation(29, 27));
var baseType = comp.GetMember<NamedTypeSymbol>("B").BaseTypeNoUseSiteDiagnostics;
VerifyParameterSymbol(baseType.GetMethod("F1A").Parameters[0], "in System.Int32 t1", RefKind.In, ScopedKind.None, expectedHasUnscopedRefAttribute: false);
VerifyParameterSymbol(baseType.GetMethod("F2A").Parameters[0], "scoped in System.Int32 t2", RefKind.In, ScopedKind.ScopedRef, expectedHasUnscopedRefAttribute: false);
VerifyParameterSymbol(baseType.GetMethod("F3A").Parameters[0], "in System.Int32 t3", RefKind.In, ScopedKind.None, expectedHasUnscopedRefAttribute: true);
VerifyParameterSymbol(baseType.GetMethod("F4A").Parameters[0], "in System.Int32 t4", RefKind.In, ScopedKind.None, expectedHasUnscopedRefAttribute: true);
}
[Fact]
public void UnscopedRefAttribute_RefStructParameter_01()
{
var source =
@"using System.Diagnostics.CodeAnalysis;
public ref struct R<T>
{
public ref T F;
public R(ref T t) { F = ref t; }
}
public class A<T>
{
public ref T F1A(R<T> r1)
{
return ref r1.F;
}
public ref T F2A(scoped R<T> r2)
{
throw null;
}
public ref T F3A([UnscopedRef] R<T> r3)
{
return ref r3.F;
}
public ref T F4A([UnscopedRef] scoped R<T> r4)
{
return ref r4.F;
}
}
class B : A<int>
{
ref int F1B()
{
int i = 1;
var r = new R<int>(ref i);
return ref F1A(r); // 1
}
ref int F2B()
{
int i = 2;
var r = new R<int>(ref i);
return ref F2A(r);
}
ref int F3B()
{
int i = 3;
var r = new R<int>(ref i);
return ref F3A(r); // 2
}
ref int F4B()
{
int i = 4;
var r = new R<int>(ref i);
return ref F4A(r); // 3
}
}";
var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70);
comp.VerifyEmitDiagnostics(
// (17,23): error CS9063: UnscopedRefAttribute cannot be applied to this parameter because it is unscoped by default.
// public ref T F3A([UnscopedRef] R<T> r3)
Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedTarget, "UnscopedRef").WithLocation(17, 23),
// (21,23): error CS9063: UnscopedRefAttribute cannot be applied to this parameter because it is unscoped by default.
// public ref T F4A([UnscopedRef] scoped R<T> r4)
Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedTarget, "UnscopedRef").WithLocation(21, 23),
// (32,20): error CS8347: Cannot use a result of 'A<int>.F1A(R<int>)' in this context because it may expose variables referenced by parameter 'r1' outside of their declaration scope
// return ref F1A(r); // 1
Diagnostic(ErrorCode.ERR_EscapeCall, "F1A(r)").WithArguments("A<int>.F1A(R<int>)", "r1").WithLocation(32, 20),
// (32,24): error CS8352: Cannot use variable 'r' in this context because it may expose referenced variables outside of their declaration scope
// return ref F1A(r); // 1
Diagnostic(ErrorCode.ERR_EscapeVariable, "r").WithArguments("r").WithLocation(32, 24),
// (44,20): error CS8347: Cannot use a result of 'A<int>.F3A(R<int>)' in this context because it may expose variables referenced by parameter 'r3' outside of their declaration scope
// return ref F3A(r); // 2
Diagnostic(ErrorCode.ERR_EscapeCall, "F3A(r)").WithArguments("A<int>.F3A(R<int>)", "r3").WithLocation(44, 20),
// (44,24): error CS8352: Cannot use variable 'r' in this context because it may expose referenced variables outside of their declaration scope
// return ref F3A(r); // 2
Diagnostic(ErrorCode.ERR_EscapeVariable, "r").WithArguments("r").WithLocation(44, 24),
// (50,20): error CS8347: Cannot use a result of 'A<int>.F4A(R<int>)' in this context because it may expose variables referenced by parameter 'r4' outside of their declaration scope
// return ref F4A(r); // 3
Diagnostic(ErrorCode.ERR_EscapeCall, "F4A(r)").WithArguments("A<int>.F4A(R<int>)", "r4").WithLocation(50, 20),
// (50,24): error CS8352: Cannot use variable 'r' in this context because it may expose referenced variables outside of their declaration scope
// return ref F4A(r); // 3
Diagnostic(ErrorCode.ERR_EscapeVariable, "r").WithArguments("r").WithLocation(50, 24));
var baseType = comp.GetMember<NamedTypeSymbol>("B").BaseTypeNoUseSiteDiagnostics;
VerifyParameterSymbol(baseType.GetMethod("F1A").Parameters[0], "R<System.Int32> r1", RefKind.None, ScopedKind.None, expectedHasUnscopedRefAttribute: false);
VerifyParameterSymbol(baseType.GetMethod("F2A").Parameters[0], "scoped R<System.Int32> r2", RefKind.None, ScopedKind.ScopedValue, expectedHasUnscopedRefAttribute: false);
VerifyParameterSymbol(baseType.GetMethod("F3A").Parameters[0], "R<System.Int32> r3", RefKind.None, ScopedKind.None, expectedHasUnscopedRefAttribute: true);
VerifyParameterSymbol(baseType.GetMethod("F4A").Parameters[0], "R<System.Int32> r4", RefKind.None, ScopedKind.None, expectedHasUnscopedRefAttribute: true);
}
[Fact]
public void UnscopedRefAttribute_RefStructParameter_02()
{
var source =
@"using System.Diagnostics.CodeAnalysis;
public ref struct R<T>
{
public ref T F;
}
class Program
{
static void F1<T>([UnscopedRef] R<T> r1) { } // 1
static void F2<T>([UnscopedRef] ref R<T> r2) { }
static void F3<T>([UnscopedRef] in R<T> r3) { }
static void F4<T>([UnscopedRef] out R<T> r4) { r4 = default; }
}";
var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70);
comp.VerifyEmitDiagnostics(
// (8,24): error CS9063: UnscopedRefAttribute cannot be applied to this parameter because it is unscoped by default.
// static void F1<T>([UnscopedRef] R<T> r1) { } // 1
Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedTarget, "UnscopedRef").WithLocation(8, 24));
VerifyParameterSymbol(comp.GetMember<MethodSymbol>("Program.F1").Parameters[0], "R<T> r1", RefKind.None, ScopedKind.None, expectedHasUnscopedRefAttribute: true);
VerifyParameterSymbol(comp.GetMember<MethodSymbol>("Program.F2").Parameters[0], "ref R<T> r2", RefKind.Ref, ScopedKind.None, expectedHasUnscopedRefAttribute: true);
VerifyParameterSymbol(comp.GetMember<MethodSymbol>("Program.F3").Parameters[0], "in R<T> r3", RefKind.In, ScopedKind.None, expectedHasUnscopedRefAttribute: true);
VerifyParameterSymbol(comp.GetMember<MethodSymbol>("Program.F4").Parameters[0], "out R<T> r4", RefKind.Out, ScopedKind.None, expectedHasUnscopedRefAttribute: true);
}
[Fact]
public void UnscopedRefAttribute_Overrides_01()
{
var source =
@"using System.Diagnostics.CodeAnalysis;
abstract class A<T>
{
internal abstract ref T F1(out T t);
internal abstract ref T F2([UnscopedRef] out T t);
}
class B1 : A<int>
{
internal override ref int F1(out int i) => throw null;
internal override ref int F2([UnscopedRef] out int i) => throw null;
}
class B2 : A<int>
{
internal override ref int F1([UnscopedRef] out int i) => throw null; // 1
internal override ref int F2(out int i) => throw null;
}
";
var comp = CreateCompilation(new[] { source, UnscopedRefAttributeDefinition });
comp.VerifyDiagnostics(
// (14,31): error CS8987: The 'scoped' modifier of parameter 'i' doesn't match overridden or implemented member.
// internal override ref int F1([UnscopedRef] out int i) => throw null; // 1
Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfOverrideOrImplementation, "F1").WithArguments("i").WithLocation(14, 31));
}
[Fact]
public void UnscopedRefAttribute_Overrides_02()
{
var source =
@"using System.Diagnostics.CodeAnalysis;
abstract class A<T>
{
internal abstract ref T F1(ref T t);
internal abstract ref T F2([UnscopedRef] ref T t);
}
class B1 : A<int>
{
internal override ref int F1(ref int i) => throw null;
internal override ref int F2([UnscopedRef] ref int i) => throw null;
}
class B2 : A<int>
{
internal override ref int F1([UnscopedRef] ref int i) => throw null; // 1
internal override ref int F2(ref int i) => throw null;
}
";
var comp = CreateCompilation(new[] { source, UnscopedRefAttributeDefinition });
comp.VerifyDiagnostics(
// (14,31): error CS8987: The 'scoped' modifier of parameter 'i' doesn't match overridden or implemented member.
// internal override ref int F1([UnscopedRef] ref int i) => throw null; // 1
Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfOverrideOrImplementation, "F1").WithArguments("i").WithLocation(14, 31));
}
[Fact]
public void UnscopedRefAttribute_Overrides_03()
{
var source =
@"using System.Diagnostics.CodeAnalysis;
ref struct R<T>
{
}
abstract class A<T>
{
internal abstract ref T F1(ref R<T> r);
internal abstract ref T F2([UnscopedRef] ref R<T> r);
}
class B1 : A<int>
{
internal override ref int F1(ref R<int> r) => throw null;
internal override ref int F2([UnscopedRef] ref R<int> r) => throw null;
}
class B2 : A<int>
{
internal override ref int F1([UnscopedRef] ref R<int> r) => throw null; // 1
internal override ref int F2(ref R<int> r) => throw null;
}
";
var comp = CreateCompilation(new[] { source, UnscopedRefAttributeDefinition });
comp.VerifyDiagnostics(
// (17,31): error CS8987: The 'scoped' modifier of parameter 'r' doesn't match overridden or implemented member.
// internal override ref int F1([UnscopedRef] ref R<int> r) => throw null; // 1
Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfOverrideOrImplementation, "F1").WithArguments("r").WithLocation(17, 31));
}
[Fact]
public void UnscopedRefAttribute_Implementations_01()
{
var source =
@"using System.Diagnostics.CodeAnalysis;
interface I<T>
{
ref readonly T F1(out T t);
ref readonly T F2([UnscopedRef] out T t);
}
class C1 : I<int>
{
public ref readonly int F1(out int i) => throw null;
public ref readonly int F2([UnscopedRef] out int i) => throw null;
}
class C2 : I<int>
{
public ref readonly int F1([UnscopedRef] out int i) => throw null; // 1
public ref readonly int F2(out int i) => throw null;
}
class C3 : I<object>
{
ref readonly object I<object>.F1(out object o) => throw null;
ref readonly object I<object>.F2([UnscopedRef] out object o) => throw null;
}
class C4 : I<object>
{
ref readonly object I<object>.F1([UnscopedRef] out object o) => throw null; // 2
ref readonly object I<object>.F2(out object o) => throw null;
}
";
var comp = CreateCompilation(new[] { source, UnscopedRefAttributeDefinition });
comp.VerifyDiagnostics(
// (14,29): error CS8987: The 'scoped' modifier of parameter 'i' doesn't match overridden or implemented member.
// public ref readonly int F1([UnscopedRef] out int i) => throw null; // 1
Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfOverrideOrImplementation, "F1").WithArguments("i").WithLocation(14, 29),
// (24,35): error CS8987: The 'scoped' modifier of parameter 'o' doesn't match overridden or implemented member.
// ref readonly object I<object>.F1([UnscopedRef] out object o) => throw null; // 2
Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfOverrideOrImplementation, "F1").WithArguments("o").WithLocation(24, 35));
}
[Fact]
public void UnscopedRefAttribute_Implementations_02()
{
var source =
@"using System.Diagnostics.CodeAnalysis;
interface I<T>
{
ref readonly T F1(ref T t);
ref readonly T F2([UnscopedRef] ref T t);
}
class C1 : I<int>
{
public ref readonly int F1(ref int i) => throw null;
public ref readonly int F2([UnscopedRef] ref int i) => throw null;
}
class C2 : I<int>
{
public ref readonly int F1([UnscopedRef] ref int i) => throw null; // 1
public ref readonly int F2(ref int i) => throw null;
}
class C3 : I<object>
{
ref readonly object I<object>.F1(ref object o) => throw null;
ref readonly object I<object>.F2([UnscopedRef] ref object o) => throw null;
}
class C4 : I<object>
{
ref readonly object I<object>.F1([UnscopedRef] ref object o) => throw null; // 2
ref readonly object I<object>.F2(ref object o) => throw null;
}
";
var comp = CreateCompilation(new[] { source, UnscopedRefAttributeDefinition });
comp.VerifyDiagnostics(
// (14,29): error CS8987: The 'scoped' modifier of parameter 'i' doesn't match overridden or implemented member.
// public ref readonly int F1([UnscopedRef] ref int i) => throw null; // 1
Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfOverrideOrImplementation, "F1").WithArguments("i").WithLocation(14, 29),
// (24,35): error CS8987: The 'scoped' modifier of parameter 'o' doesn't match overridden or implemented member.
// ref readonly object I<object>.F1([UnscopedRef] ref object o) => throw null; // 2
Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfOverrideOrImplementation, "F1").WithArguments("o").WithLocation(24, 35));
}
[Fact]
public void ScopedRefToRefStruct_Implementations_03()
{
var source =
@"
ref struct R<T>
{
}
interface I<T>
{
ref readonly T F1(scoped ref R<T> r);
ref readonly T F2(ref R<T> r);
}
class C1 : I<int>
{
public ref readonly int F1(scoped ref R<int> r) => throw null;
public ref readonly int F2(ref R<int> r) => throw null;
}
class C2 : I<int>
{
public ref readonly int F1(ref R<int> r) => throw null; // 1
public ref readonly int F2(scoped ref R<int> r) => throw null;
}
class C3 : I<object>
{
ref readonly object I<object>.F1(scoped ref R<object> r) => throw null;
ref readonly object I<object>.F2(ref R<object> r) => throw null;
}
class C4 : I<object>
{
ref readonly object I<object>.F1(ref R<object> r) => throw null; // 2
ref readonly object I<object>.F2(scoped ref R<object> r) => throw null;
}
";
var comp = CreateCompilation(new[] { source, UnscopedRefAttributeDefinition });
comp.VerifyDiagnostics(
// (17,29): error CS8987: The 'scoped' modifier of parameter 'r' doesn't match overridden or implemented member.
// public ref readonly int F1(ref R<int> r) => throw null; // 1
Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfOverrideOrImplementation, "F1").WithArguments("r").WithLocation(17, 29),
// (27,35): error CS8987: The 'scoped' modifier of parameter 'r' doesn't match overridden or implemented member.
// ref readonly object I<object>.F1(ref R<object> r) => throw null; // 2
Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfOverrideOrImplementation, "F1").WithArguments("r").WithLocation(27, 35));
}
[Fact]
public void UnscopedRefAttribute_Delegates_01()
{
var source =
@"using System.Diagnostics.CodeAnalysis;
delegate ref T D1<T>(out T t);
delegate ref T D2<T>([UnscopedRef] out T t);
class Program
{
static void Main()
{
D1<int> d1;
d1 = (out int i1) => { i1 = 1; return ref F<int>(); };
d1 = ([UnscopedRef] out int i2) => { i2 = 2; return ref F<int>(); }; // 1
D2<object> d2;
d2 = (out object o1) => { o1 = 1; return ref F<object>(); };
d2 = ([UnscopedRef] out object o2) => { o2 = 2; return ref F<object>(); };
}
static ref T F<T>() => throw null;
}";
var comp = CreateCompilation(new[] { source, UnscopedRefAttributeDefinition });
comp.VerifyDiagnostics(
// (10,14): error CS8986: The 'scoped' modifier of parameter 'i2' doesn't match target 'D1<int>'.
// d1 = ([UnscopedRef] out int i2) => { i2 = 2; return ref F<int>(); }; // 1
Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "([UnscopedRef] out int i2) => { i2 = 2; return ref F<int>(); }").WithArguments("i2", "D1<int>").WithLocation(10, 14));
var tree = comp.SyntaxTrees[0];
var model = comp.GetSemanticModel(tree);
var lambdas = tree.GetRoot().DescendantNodes().OfType<ParenthesizedLambdaExpressionSyntax>().Select(e => model.GetSymbolInfo(e).Symbol.GetSymbol<LambdaSymbol>()).ToArray();
VerifyParameterSymbol(lambdas[0].Parameters[0], "out System.Int32 i1", RefKind.Out, ScopedKind.ScopedRef, expectedHasUnscopedRefAttribute: false);
VerifyParameterSymbol(lambdas[1].Parameters[0], "out System.Int32 i2", RefKind.Out, ScopedKind.None, expectedHasUnscopedRefAttribute: true);
VerifyParameterSymbol(lambdas[2].Parameters[0], "out System.Object o1", RefKind.Out, ScopedKind.ScopedRef, expectedHasUnscopedRefAttribute: false);
VerifyParameterSymbol(lambdas[3].Parameters[0], "out System.Object o2", RefKind.Out, ScopedKind.None, expectedHasUnscopedRefAttribute: true);
}
[Fact]
public void UnscopedRefAttribute_Delegates_02()
{
var source =
@"using System.Diagnostics.CodeAnalysis;
delegate ref T D1<T>(ref T t);
delegate ref T D2<T>([UnscopedRef] ref T t);
class Program
{
static void Main()
{
D1<int> d1;
d1 = (ref int i1) => ref F<int>();
d1 = ([UnscopedRef] ref int i2) => ref F<int>(); // 1
D2<object> d2;
d2 = (ref object o1) => ref F<object>();
d2 = ([UnscopedRef] ref object o2) => ref F<object>();
}
static ref T F<T>() => throw null;
}";
var comp = CreateCompilation(new[] { source, UnscopedRefAttributeDefinition });
comp.VerifyDiagnostics(
// (10,14): error CS8986: The 'scoped' modifier of parameter 'i2' doesn't match target 'D1<int>'.
// d1 = ([UnscopedRef] ref int i2) => ref F<int>();
Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "([UnscopedRef] ref int i2) => ref F<int>()").WithArguments("i2", "D1<int>").WithLocation(10, 14));
var tree = comp.SyntaxTrees[0];
var model = comp.GetSemanticModel(tree);
var lambdas = tree.GetRoot().DescendantNodes().OfType<ParenthesizedLambdaExpressionSyntax>().Select(e => model.GetSymbolInfo(e).Symbol.GetSymbol<LambdaSymbol>()).ToArray();
VerifyParameterSymbol(lambdas[0].Parameters[0], "ref System.Int32 i1", RefKind.Ref, ScopedKind.None, expectedHasUnscopedRefAttribute: false);
VerifyParameterSymbol(lambdas[1].Parameters[0], "ref System.Int32 i2", RefKind.Ref, ScopedKind.None, expectedHasUnscopedRefAttribute: true);
VerifyParameterSymbol(lambdas[2].Parameters[0], "ref System.Object o1", RefKind.Ref, ScopedKind.None, expectedHasUnscopedRefAttribute: false);
VerifyParameterSymbol(lambdas[3].Parameters[0], "ref System.Object o2", RefKind.Ref, ScopedKind.None, expectedHasUnscopedRefAttribute: true);
}
[Fact]
public void UnscopedRefAttribute_Delegates_03()
{
var source =
@"
ref struct R<T> { }
delegate ref readonly T D1<T>(scoped ref R<T> r);
delegate ref readonly T D2<T>(ref R<T> r);
class Program
{
static void Main()
{
D1<int> d1;
d1 = (scoped ref R<int> r1) => ref F<int>();
d1 = (ref R<int> r2) => ref F<int>(); // 1
D2<object> d2;
d2 = (scoped ref R<object> r1) => ref F<object>();
d2 = (ref R<object> r2) => ref F<object>();
}
static ref readonly T F<T>() => throw null;
}";
var comp = CreateCompilation(source);
comp.VerifyDiagnostics(
// (11,14): error CS8986: The 'scoped' modifier of parameter 'r2' doesn't match target 'D1<int>'.
// d1 = (ref R<int> r2) => ref F<int>(); // 1
Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "(ref R<int> r2) => ref F<int>()").WithArguments("r2", "D1<int>").WithLocation(11, 14));
var tree = comp.SyntaxTrees[0];
var model = comp.GetSemanticModel(tree);
var lambdas = tree.GetRoot().DescendantNodes().OfType<ParenthesizedLambdaExpressionSyntax>().Select(e => model.GetSymbolInfo(e).Symbol.GetSymbol<LambdaSymbol>()).ToArray();
VerifyParameterSymbol(lambdas[0].Parameters[0], "scoped ref R<System.Int32> r1", RefKind.Ref, ScopedKind.ScopedRef, expectedHasUnscopedRefAttribute: false);
VerifyParameterSymbol(lambdas[1].Parameters[0], "ref R<System.Int32> r2", RefKind.Ref, ScopedKind.None, expectedHasUnscopedRefAttribute: false);
VerifyParameterSymbol(lambdas[2].Parameters[0], "scoped ref R<System.Object> r1", RefKind.Ref, ScopedKind.ScopedRef, expectedHasUnscopedRefAttribute: false);
VerifyParameterSymbol(lambdas[3].Parameters[0], "ref R<System.Object> r2", RefKind.Ref, ScopedKind.None, expectedHasUnscopedRefAttribute: false);
}
[WorkItem(64569, "https://github.com/dotnet/roslyn/issues/64569")]
[Fact]
public void UnscopedRefAttribute_RefParameter_01()
{
var source =
@"using System.Diagnostics.CodeAnalysis;
ref struct R
{
public R(in int i) { }
void SetRef(ref int i1)
{
this = new R(in i1); // 1
}
void SetIn(in int i2)
{
this = new R(in i2); // 2
}
void SetOut(out int i3)
{
i3 = 0;
this = new R(in i3); // 3
}
void SetUnscopedRef([UnscopedRef] ref int i4)
{
this = new R(in i4);
}
void SetUnscopedIn([UnscopedRef] in int i5)
{
this = new R(in i5);
}
void SetUnscopedOut([UnscopedRef] out int i6)
{
i6 = 0;
this = new R(in i6); // 4
}
}";
var comp = CreateCompilation(new[] { source, UnscopedRefAttributeDefinition });
comp.VerifyDiagnostics(
// (7,16): error CS8347: Cannot use a result of 'R.R(in int)' in this context because it may expose variables referenced by parameter 'i' outside of their declaration scope
// this = new R(in i1); // 1
Diagnostic(ErrorCode.ERR_EscapeCall, "new R(in i1)").WithArguments("R.R(in int)", "i").WithLocation(7, 16),
// (7,25): error CS9077: Cannot return a parameter by reference 'i1' through a ref parameter; it can only be returned in a return statement
// this = new R(in i1); // 1
Diagnostic(ErrorCode.ERR_RefReturnOnlyParameter, "i1").WithArguments("i1").WithLocation(7, 25),
// (11,16): error CS8347: Cannot use a result of 'R.R(in int)' in this context because it may expose variables referenced by parameter 'i' outside of their declaration scope
// this = new R(in i2); // 2
Diagnostic(ErrorCode.ERR_EscapeCall, "new R(in i2)").WithArguments("R.R(in int)", "i").WithLocation(11, 16),
// (11,25): error CS9077: Cannot return a parameter by reference 'i2' through a ref parameter; it can only be returned in a return statement
// this = new R(in i2); // 2
Diagnostic(ErrorCode.ERR_RefReturnOnlyParameter, "i2").WithArguments("i2").WithLocation(11, 25),
// (16,16): error CS8347: Cannot use a result of 'R.R(in int)' in this context because it may expose variables referenced by parameter 'i' outside of their declaration scope
// this = new R(in i3); // 3
Diagnostic(ErrorCode.ERR_EscapeCall, "new R(in i3)").WithArguments("R.R(in int)", "i").WithLocation(16, 16),
// (16,25): error CS9075: Cannot return a parameter by reference 'i3' because it is scoped to the current method
// this = new R(in i3); // 3
Diagnostic(ErrorCode.ERR_RefReturnScopedParameter, "i3").WithArguments("i3").WithLocation(16, 25),
// (29,16): error CS8347: Cannot use a result of 'R.R(in int)' in this context because it may expose variables referenced by parameter 'i' outside of their declaration scope
// this = new R(in i6); // 4
Diagnostic(ErrorCode.ERR_EscapeCall, "new R(in i6)").WithArguments("R.R(in int)", "i").WithLocation(29, 16),
// (29,25): error CS9077: Cannot return a parameter by reference 'i6' through a ref parameter; it can only be returned in a return statement
// this = new R(in i6); // 4
Diagnostic(ErrorCode.ERR_RefReturnOnlyParameter, "i6").WithArguments("i6").WithLocation(29, 25));
}
[WorkItem(64569, "https://github.com/dotnet/roslyn/issues/64569")]
[Fact]
public void UnscopedRefAttribute_RefParameter_02()
{
var source =
@"using System.Diagnostics.CodeAnalysis;
ref struct R
{
private ref readonly int _i;
void SetRef(ref int i1)
{
_i = ref i1; // 1
}
void SetIn(in int i2)
{
_i = ref i2; // 2
}
void SetOut(out int i3)
{
i3 = 0;
_i = ref i3; // 3
}
void SetUnscopedRef([UnscopedRef] ref int i4)
{
_i = ref i4;
}
void SetUnscopedIn([UnscopedRef] in int i5)
{
_i = ref i5;
}
void SetUnscopedOut([UnscopedRef] out int i6)
{
i6 = 0;
_i = ref i6; // 4
}
}";
var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70);
comp.VerifyDiagnostics(
// (7,9): error CS9079: Cannot ref-assign 'i1' to '_i' because 'i1' can only escape the current method through a return statement.
// _i = ref i1; // 1
Diagnostic(ErrorCode.ERR_RefAssignReturnOnly, "_i = ref i1").WithArguments("_i", "i1").WithLocation(7, 9),
// (11,9): error CS9079: Cannot ref-assign 'i2' to '_i' because 'i2' can only escape the current method through a return statement.
// _i = ref i2; // 2
Diagnostic(ErrorCode.ERR_RefAssignReturnOnly, "_i = ref i2").WithArguments("_i", "i2").WithLocation(11, 9),
// (16,9): error CS8374: Cannot ref-assign 'i3' to '_i' because 'i3' has a narrower escape scope than '_i'.
// _i = ref i3; // 3
Diagnostic(ErrorCode.ERR_RefAssignNarrower, "_i = ref i3").WithArguments("_i", "i3").WithLocation(16, 9),
// (29,9): error CS9079: Cannot ref-assign 'i6' to '_i' because 'i6' can only escape the current method through a return statement.
// _i = ref i6; // 4
Diagnostic(ErrorCode.ERR_RefAssignReturnOnly, "_i = ref i6").WithArguments("_i", "i6").WithLocation(29, 9));
}
[Theory]
[CombinatorialData]
public void UnscopedRefAttribute_RefParameter_03(bool useCompilationReference)
{
var sourceA =
@"using System.Diagnostics.CodeAnalysis;
public ref struct R1<T>
{
public R1(ref T t) { }
}
public ref struct R2<T>
{
public R2(in T t) { }
}
public class A<T>
{
public static ref T Ref(ref T t1, ref R1<T> r1)
{
return ref t1;
}
public static ref T UnscopedRef([UnscopedRef] ref T t2, ref R1<T> r2)
{
r2 = new R1<T>(ref t2);
return ref t2;
}
public static ref readonly T In(in T t3, ref R2<T> r3)
{
return ref t3;
}
public static ref readonly T UnscopedIn([UnscopedRef] in T t4, ref R2<T> r4)
{
r4 = new R2<T>(in t4);
return ref t4;
}
public static ref T Out(out T t5)
{
t5 = default;
throw null;
}
public static ref T UnscopedOut([UnscopedRef] out T t6)
{
t6 = default;
return ref t6;
}
}";
var comp = CreateCompilation(new[] { sourceA, UnscopedRefAttributeDefinition });
comp.VerifyEmitDiagnostics();
var refA = AsReference(comp, useCompilationReference);
var sourceB =
@"class B : A<int>
{
static void F1(ref R1<int> r1)
{
int i1 = 1;
Ref(ref i1, ref r1);
}
static void F2(ref R1<int> r2)
{
int i2 = 2;
UnscopedRef(ref i2, ref r2); // 1
}
static void F3(ref R2<int> r3)
{
int i3 = 3;
In(in i3, ref r3);
}
static void F4(ref R2<int> r4)
{
int i4 = 4;
UnscopedIn(in i4, ref r4); // 2
}
static ref int F5()
{
int i5;
return ref Out(out i5);
}
static ref int F6()
{
int i6;
return ref UnscopedOut(out i6); // 3
}
}";
comp = CreateCompilation(new[] { sourceB, UnscopedRefAttributeDefinition }, references: new[] { refA });
comp.VerifyEmitDiagnostics(
// (11,9): error CS8350: This combination of arguments to 'A<int>.UnscopedRef(ref int, ref R1<int>)' is disallowed because it may expose variables referenced by parameter 't2' outside of their declaration scope
// UnscopedRef(ref i2, ref r2); // 1
Diagnostic(ErrorCode.ERR_CallArgMixing, "UnscopedRef(ref i2, ref r2)").WithArguments("A<int>.UnscopedRef(ref int, ref R1<int>)", "t2").WithLocation(11, 9),
// (11,25): error CS8168: Cannot return local 'i2' by reference because it is not a ref local
// UnscopedRef(ref i2, ref r2); // 1
Diagnostic(ErrorCode.ERR_RefReturnLocal, "i2").WithArguments("i2").WithLocation(11, 25),
// (21,9): error CS8350: This combination of arguments to 'A<int>.UnscopedIn(in int, ref R2<int>)' is disallowed because it may expose variables referenced by parameter 't4' outside of their declaration scope
// UnscopedIn(in i4, ref r4); // 2
Diagnostic(ErrorCode.ERR_CallArgMixing, "UnscopedIn(in i4, ref r4)").WithArguments("A<int>.UnscopedIn(in int, ref R2<int>)", "t4").WithLocation(21, 9),
// (21,23): error CS8168: Cannot return local 'i4' by reference because it is not a ref local
// UnscopedIn(in i4, ref r4); // 2
Diagnostic(ErrorCode.ERR_RefReturnLocal, "i4").WithArguments("i4").WithLocation(21, 23),
// (31,20): error CS8347: Cannot use a result of 'A<int>.UnscopedOut(out int)' in this context because it may expose variables referenced by parameter 't6' outside of their declaration scope
// return ref UnscopedOut(out i6); // 3
Diagnostic(ErrorCode.ERR_EscapeCall, "UnscopedOut(out i6)").WithArguments("A<int>.UnscopedOut(out int)", "t6").WithLocation(31, 20),
// (31,36): error CS8168: Cannot return local 'i6' by reference because it is not a ref local
// return ref UnscopedOut(out i6); // 3
Diagnostic(ErrorCode.ERR_RefReturnLocal, "i6").WithArguments("i6").WithLocation(31, 36));
}
[Fact]
public void UnscopedRefAttribute_Cycle()
{
var source =
@"namespace System.Diagnostics.CodeAnalysis
{
public sealed class UnscopedRefAttribute : Attribute
{
public UnscopedRefAttribute([UnscopedRef] out int i) { i = 0; }
}
}";
var comp = CreateCompilation(source);
comp.VerifyDiagnostics(
// (5,38): error CS7036: There is no argument given that corresponds to the required parameter 'i' of 'UnscopedRefAttribute.UnscopedRefAttribute(out int)'
// public UnscopedRefAttribute([UnscopedRef] out int i) { i = 0; }
Diagnostic(ErrorCode.ERR_NoCorrespondingArgument, "UnscopedRef").WithArguments("i", "System.Diagnostics.CodeAnalysis.UnscopedRefAttribute.UnscopedRefAttribute(out int)").WithLocation(5, 38));
}
[Fact]
public void UnscopedRefAttribute_UnexpectedConstructorArgument()
{
var sourceA =
@"namespace System.Diagnostics.CodeAnalysis
{
public sealed class UnscopedRefAttribute : Attribute
{
public UnscopedRefAttribute(bool b) { }
}
}";
var sourceB =
@"using System.Diagnostics.CodeAnalysis;
class Program
{
static ref int F1([UnscopedRef] out int i1)
{
i1 = 0;
return ref i1;
}
static ref int F2([UnscopedRef(true)] out int i2)
{
i2 = 0;
return ref i2;
}
static ref int F3()
{
int i3;
return ref F1(out i3);
}
static ref int F4()
{
int i4;
return ref F2(out i4);
}
}";
var comp = CreateCompilation(new[] { sourceA, sourceB });
comp.VerifyDiagnostics(
// (4,24): error CS7036: There is no argument given that corresponds to the required parameter 'b' of 'UnscopedRefAttribute.UnscopedRefAttribute(bool)'
// static ref int F1([UnscopedRef] out int i1)
Diagnostic(ErrorCode.ERR_NoCorrespondingArgument, "UnscopedRef").WithArguments("b", "System.Diagnostics.CodeAnalysis.UnscopedRefAttribute.UnscopedRefAttribute(bool)").WithLocation(4, 24),
// (12,20): error CS9075: Cannot return a parameter by reference 'i2' because it is scoped to the current method
// return ref i2;
Diagnostic(ErrorCode.ERR_RefReturnScopedParameter, "i2").WithArguments("i2").WithLocation(12, 20),
// (17,20): error CS8347: Cannot use a result of 'Program.F1(out int)' in this context because it may expose variables referenced by parameter 'i1' outside of their declaration scope
// return ref F1(out i3);
Diagnostic(ErrorCode.ERR_EscapeCall, "F1(out i3)").WithArguments("Program.F1(out int)", "i1").WithLocation(17, 20),
// (17,27): error CS8168: Cannot return local 'i3' by reference because it is not a ref local
// return ref F1(out i3);
Diagnostic(ErrorCode.ERR_RefReturnLocal, "i3").WithArguments("i3").WithLocation(17, 27));
}
[Fact]
public void UnscopedRefAttribute_InvalidConstructorArgument()
{
var sourceA =
@"namespace System.Diagnostics.CodeAnalysis
{
public sealed class UnscopedRefAttribute : Attribute
{
public UnscopedRefAttribute(bool b) { }
}
}";
var sourceB =
@"using System.Diagnostics.CodeAnalysis;
class Program
{
static bool F1()
{
return true;
}
static ref int F2([UnscopedRef(F1())] out int i)
{
i = 0;
return ref i;
}
}";
var comp = CreateCompilation(new[] { sourceA, sourceB });
comp.VerifyDiagnostics(
// (8,36): error CS0182: An attribute argument must be a constant expression, typeof expression or array creation expression of an attribute parameter type
// static ref int F2([UnscopedRef(F1())] out int i)
Diagnostic(ErrorCode.ERR_BadAttributeArgument, "F1()").WithLocation(8, 36),
// (11,20): error CS9075: Cannot return a parameter by reference 'i' because it is scoped to the current method
// return ref i;
Diagnostic(ErrorCode.ERR_RefReturnScopedParameter, "i").WithArguments("i").WithLocation(11, 20));
}
[Fact]
public void UnscopedRefAttribute_ScopeRefAttribute_Out()
{
var sourceA =
@".assembly extern mscorlib { .ver 4:0:0:0 .publickeytoken = (B7 7A 5C 56 19 34 E0 89) }
.assembly '<<GeneratedFileName>>' { }
.module '<<GeneratedFileName>>.dll'
.custom instance void System.Runtime.CompilerServices.RefSafetyRulesAttribute::.ctor(int32) = { int32(11) }
.class private System.Runtime.CompilerServices.RefSafetyRulesAttribute extends [mscorlib]System.Attribute
{
.method public hidebysig specialname rtspecialname instance void .ctor(int32 version) cil managed { ret }
.field public int32 Version
}
.class private System.Diagnostics.CodeAnalysis.UnscopedRefAttribute extends [mscorlib]System.Attribute
{
.method public hidebysig specialname rtspecialname instance void .ctor() cil managed { ret }
}
.class private System.Runtime.CompilerServices.ScopedRefAttribute extends [mscorlib]System.Attribute
{
.method public hidebysig specialname rtspecialname instance void .ctor() cil managed { ret }
}
.class public A
{
.method public static int32& NoAttributes([out] int32& i)
{
ldnull
throw
}
.method public static int32& ScopedRefOnly([out] int32& i)
{
.param [1]
.custom instance void System.Runtime.CompilerServices.ScopedRefAttribute::.ctor() = ( 01 00 00 00 )
ldnull
throw
}
.method public static int32& UnscopedRefOnly([out] int32& i)
{
.param [1]
.custom instance void System.Diagnostics.CodeAnalysis.UnscopedRefAttribute::.ctor() = ( 01 00 00 00 )
ldnull
throw
}
.method public static int32& ScopedRefAndUnscopedRef([out] int32& i)
{
.param [1]
.custom instance void System.Diagnostics.CodeAnalysis.UnscopedRefAttribute::.ctor() = ( 01 00 00 00 )
.param [1]
.custom instance void System.Runtime.CompilerServices.ScopedRefAttribute::.ctor() = ( 01 00 00 00 )
ldnull
throw
}
}
";
var refA = CompileIL(sourceA, prependDefaultHeader: false);
var sourceB =
@"class Program
{
static ref int F1()
{
int i;
return ref A.NoAttributes(out i);
}
static ref int F2()
{
int i;
return ref A.ScopedRefOnly(out i);
}
static ref int F3()
{
int i;
return ref A.UnscopedRefOnly(out i); // 1
}
static ref int F4()
{
int i;
return ref A.ScopedRefAndUnscopedRef(out i); // 2
}
}";
var comp = CreateCompilation(sourceB, new[] { refA });
comp.VerifyEmitDiagnostics(
// (16,20): error CS8347: Cannot use a result of 'A.UnscopedRefOnly(out int)' in this context because it may expose variables referenced by parameter 'i' outside of their declaration scope
// return ref A.UnscopedRefOnly(out i); // 1
Diagnostic(ErrorCode.ERR_EscapeCall, "A.UnscopedRefOnly(out i)").WithArguments("A.UnscopedRefOnly(out int)", "i").WithLocation(16, 20),
// (16,42): error CS8168: Cannot return local 'i' by reference because it is not a ref local
// return ref A.UnscopedRefOnly(out i); // 1
Diagnostic(ErrorCode.ERR_RefReturnLocal, "i").WithArguments("i").WithLocation(16, 42),
// (21,22): error CS0570: 'A.ScopedRefAndUnscopedRef(out int)' is not supported by the language
// return ref A.ScopedRefAndUnscopedRef(out i); // 2
Diagnostic(ErrorCode.ERR_BindToBogus, "ScopedRefAndUnscopedRef").WithArguments("A.ScopedRefAndUnscopedRef(out int)").WithLocation(21, 22));
var typeA = comp.GetMember<NamedTypeSymbol>("A");
VerifyParameterSymbol(typeA.GetMethod("NoAttributes").Parameters[0], "out System.Int32 i", RefKind.Out, ScopedKind.ScopedRef, expectedHasUnscopedRefAttribute: false);
VerifyParameterSymbol(typeA.GetMethod("ScopedRefOnly").Parameters[0], "out System.Int32 i", RefKind.Out, ScopedKind.ScopedRef, expectedHasUnscopedRefAttribute: false);
VerifyParameterSymbol(typeA.GetMethod("UnscopedRefOnly").Parameters[0], "out System.Int32 i", RefKind.Out, ScopedKind.None, expectedHasUnscopedRefAttribute: true);
VerifyParameterSymbol(typeA.GetMethod("ScopedRefAndUnscopedRef").Parameters[0], "out System.Int32 i", RefKind.Out, ScopedKind.None, expectedHasUnscopedRefAttribute: true);
}
[WorkItem(64778, "https://github.com/dotnet/roslyn/issues/64778")]
[Fact]
public void UnscopedRefAttribute_ScopeRefAttribute_RefToRefStruct()
{
// class A
// {
// static void NoAttributes(ref R x, ref R y) { }
// static void ScopedRefOnly([ScopedRef] ref R x, ref R y) { }
// static void UnscopedRefOnly([UnscopedRef] ref R x, ref R y) { }
// static void ScopedRefAndUnscopedRef([ScopedRef][UnscopedRef] ref R x, ref R y) { }
// }
var sourceA =
@".assembly extern mscorlib { .ver 4:0:0:0 .publickeytoken = (B7 7A 5C 56 19 34 E0 89) }
.assembly '<<GeneratedFileName>>' { }
.module '<<GeneratedFileName>>.dll'
.custom instance void System.Runtime.CompilerServices.RefSafetyRulesAttribute::.ctor(int32) = { int32(11) }
.class private System.Runtime.CompilerServices.RefSafetyRulesAttribute extends [mscorlib]System.Attribute
{
.method public hidebysig specialname rtspecialname instance void .ctor(int32 version) cil managed { ret }
.field public int32 Version
}
.class private System.Diagnostics.CodeAnalysis.UnscopedRefAttribute extends [mscorlib]System.Attribute
{
.method public hidebysig specialname rtspecialname instance void .ctor() cil managed { ret }
}
.class private System.Runtime.CompilerServices.ScopedRefAttribute extends [mscorlib]System.Attribute
{
.method public hidebysig specialname rtspecialname instance void .ctor() cil managed { ret }
}
.class public sealed R extends [mscorlib]System.ValueType
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.IsByRefLikeAttribute::.ctor() = (01 00 00 00)
.field public int32& F
}
.class public A
{
.method public static void NoAttributes(valuetype R& x, valuetype R& y)
{
ret
}
.method public static void ScopedRefOnly(valuetype R& x, valuetype R& y)
{
.param [1]
.custom instance void System.Runtime.CompilerServices.ScopedRefAttribute::.ctor() = ( 01 00 00 00 )
ret
}
.method public static void UnscopedRefOnly(valuetype R& x, valuetype R& y)
{
.param [1]
.custom instance void System.Diagnostics.CodeAnalysis.UnscopedRefAttribute::.ctor() = ( 01 00 00 00 )
ret
}
.method public static void ScopedRefAndUnscopedRef(valuetype R& x, valuetype R& y)
{
.param [1]
.custom instance void System.Diagnostics.CodeAnalysis.UnscopedRefAttribute::.ctor() = ( 01 00 00 00 )
.custom instance void System.Runtime.CompilerServices.ScopedRefAttribute::.ctor() = ( 01 00 00 00 )
ret
}
}
";
var refA = CompileIL(sourceA, prependDefaultHeader: false);
var sourceB =
@"class Program
{
static void F1(ref R x, ref R y)
{
A.NoAttributes(ref x, ref y);
}
static void F2(ref R x, ref R y)
{
A.ScopedRefOnly(ref x, ref y);
}
static void F3(ref R x, ref R y)
{
A.UnscopedRefOnly(ref x, ref y); // 1
}
static void F4(ref R x, ref R y)
{
A.ScopedRefAndUnscopedRef(ref x, ref y); // 2
}
}";
var comp = CreateCompilation(sourceB, new[] { refA });
comp.VerifyEmitDiagnostics(
// (13,9): error CS8350: This combination of arguments to 'A.UnscopedRefOnly(ref R, ref R)' is disallowed because it may expose variables referenced by parameter 'x' outside of their declaration scope
// A.UnscopedRefOnly(ref x, ref y); // 1
Diagnostic(ErrorCode.ERR_CallArgMixing, "A.UnscopedRefOnly(ref x, ref y)").WithArguments("A.UnscopedRefOnly(ref R, ref R)", "x").WithLocation(13, 9),
// (13,31): error CS9077: Cannot return a parameter by reference 'x' through a ref parameter; it can only be returned in a return statement
// A.UnscopedRefOnly(ref x, ref y); // 1
Diagnostic(ErrorCode.ERR_RefReturnOnlyParameter, "x").WithArguments("x").WithLocation(13, 31),
// (17,11): error CS0570: 'A.ScopedRefAndUnscopedRef(ref R, ref R)' is not supported by the language
// A.ScopedRefAndUnscopedRef(ref x, ref y); // 2
Diagnostic(ErrorCode.ERR_BindToBogus, "ScopedRefAndUnscopedRef").WithArguments("A.ScopedRefAndUnscopedRef(ref R, ref R)").WithLocation(17, 11));
var typeA = comp.GetMember<NamedTypeSymbol>("A");
VerifyParameterSymbol(typeA.GetMethod("NoAttributes").Parameters[0], "ref R x", RefKind.Ref, ScopedKind.None, expectedHasUnscopedRefAttribute: false);
VerifyParameterSymbol(typeA.GetMethod("ScopedRefOnly").Parameters[0], "scoped ref R x", RefKind.Ref, ScopedKind.ScopedRef, expectedHasUnscopedRefAttribute: false);
VerifyParameterSymbol(typeA.GetMethod("UnscopedRefOnly").Parameters[0], "ref R x", RefKind.Ref, ScopedKind.None, expectedHasUnscopedRefAttribute: true);
VerifyParameterSymbol(typeA.GetMethod("ScopedRefAndUnscopedRef").Parameters[0], "ref R x", RefKind.Ref, ScopedKind.None, expectedHasUnscopedRefAttribute: true);
}
// As above, but with ref readonly parameters.
[WorkItem(64778, "https://github.com/dotnet/roslyn/issues/64778")]
[Fact]
public void UnscopedRefAttribute_ScopeRefAttribute_RefReadOnlyToRefStruct()
{
// class A
// {
// static void NoAttributes(in R x, ref R y) { }
// static void ScopedRefOnly([ScopedRef] in R x, ref R y) { }
// static void UnscopedRefOnly([UnscopedRef] in R x, ref R y) { }
// static void ScopedRefAndUnscopedRef([ScopedRef][UnscopedRef] in R x, ref R y) { }
// }
var sourceA =
@".assembly extern mscorlib { .ver 4:0:0:0 .publickeytoken = (B7 7A 5C 56 19 34 E0 89) }
.assembly '<<GeneratedFileName>>' { }
.module '<<GeneratedFileName>>.dll'
.custom instance void System.Runtime.CompilerServices.RefSafetyRulesAttribute::.ctor(int32) = { int32(11) }
.class private System.Runtime.CompilerServices.RefSafetyRulesAttribute extends [mscorlib]System.Attribute
{
.method public hidebysig specialname rtspecialname instance void .ctor(int32 version) cil managed { ret }
.field public int32 Version
}
.class private System.Diagnostics.CodeAnalysis.UnscopedRefAttribute extends [mscorlib]System.Attribute
{
.method public hidebysig specialname rtspecialname instance void .ctor() cil managed { ret }
}
.class private System.Runtime.CompilerServices.ScopedRefAttribute extends [mscorlib]System.Attribute
{
.method public hidebysig specialname rtspecialname instance void .ctor() cil managed { ret }
}
.class public sealed R extends [mscorlib]System.ValueType
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.IsByRefLikeAttribute::.ctor() = (01 00 00 00)
.field public int32& F
}
.class public A
{
.method public static void NoAttributes([in] valuetype R& x, valuetype R& y)
{
.param [1]
.custom instance void [mscorlib]System.Runtime.CompilerServices.IsReadOnlyAttribute::.ctor() = ( 01 00 00 00 )
ret
}
.method public static void ScopedRefOnly([in] valuetype R& x, valuetype R& y)
{
.param [1]
.custom instance void [mscorlib]System.Runtime.CompilerServices.IsReadOnlyAttribute::.ctor() = ( 01 00 00 00 )
.custom instance void System.Runtime.CompilerServices.ScopedRefAttribute::.ctor() = ( 01 00 00 00 )
ret
}
.method public static void UnscopedRefOnly([in] valuetype R& x, valuetype R& y)
{
.param [1]
.custom instance void [mscorlib]System.Runtime.CompilerServices.IsReadOnlyAttribute::.ctor() = ( 01 00 00 00 )
.custom instance void System.Diagnostics.CodeAnalysis.UnscopedRefAttribute::.ctor() = ( 01 00 00 00 )
ret
}
.method public static void ScopedRefAndUnscopedRef([in] valuetype R& x, valuetype R& y)
{
.param [1]
.custom instance void [mscorlib]System.Runtime.CompilerServices.IsReadOnlyAttribute::.ctor() = ( 01 00 00 00 )
.custom instance void System.Diagnostics.CodeAnalysis.UnscopedRefAttribute::.ctor() = ( 01 00 00 00 )
.custom instance void System.Runtime.CompilerServices.ScopedRefAttribute::.ctor() = ( 01 00 00 00 )
ret
}
}
";
var refA = CompileIL(sourceA, prependDefaultHeader: false);
var sourceB =
@"class Program
{
static void F1(in R x, ref R y)
{
A.NoAttributes(in x, ref y);
}
static void F2(in R x, ref R y)
{
A.ScopedRefOnly(in x, ref y);
}
static void F3(in R x, ref R y)
{
A.UnscopedRefOnly(in x, ref y); // 1
}
static void F4(in R x, ref R y)
{
A.ScopedRefAndUnscopedRef(in x, ref y); // 2
}
}";
var comp = CreateCompilation(sourceB, new[] { refA });
comp.VerifyEmitDiagnostics(
// (13,9): error CS8350: This combination of arguments to 'A.UnscopedRefOnly(in R, ref R)' is disallowed because it may expose variables referenced by parameter 'x' outside of their declaration scope
// A.UnscopedRefOnly(in x, ref y); // 1
Diagnostic(ErrorCode.ERR_CallArgMixing, "A.UnscopedRefOnly(in x, ref y)").WithArguments("A.UnscopedRefOnly(in R, ref R)", "x").WithLocation(13, 9),
// (13,30): error CS9077: Cannot return a parameter by reference 'x' through a ref parameter; it can only be returned in a return statement
// A.UnscopedRefOnly(in x, ref y); // 1
Diagnostic(ErrorCode.ERR_RefReturnOnlyParameter, "x").WithArguments("x").WithLocation(13, 30),
// (17,11): error CS0570: 'A.ScopedRefAndUnscopedRef(in R, ref R)' is not supported by the language
// A.ScopedRefAndUnscopedRef(in x, ref y); // 2
Diagnostic(ErrorCode.ERR_BindToBogus, "ScopedRefAndUnscopedRef").WithArguments("A.ScopedRefAndUnscopedRef(in R, ref R)").WithLocation(17, 11));
var typeA = comp.GetMember<NamedTypeSymbol>("A");
VerifyParameterSymbol(typeA.GetMethod("NoAttributes").Parameters[0], "in R x", RefKind.In, ScopedKind.None, expectedHasUnscopedRefAttribute: false);
VerifyParameterSymbol(typeA.GetMethod("ScopedRefOnly").Parameters[0], "scoped in R x", RefKind.In, ScopedKind.ScopedRef, expectedHasUnscopedRefAttribute: false);
VerifyParameterSymbol(typeA.GetMethod("UnscopedRefOnly").Parameters[0], "in R x", RefKind.In, ScopedKind.None, expectedHasUnscopedRefAttribute: true);
VerifyParameterSymbol(typeA.GetMethod("ScopedRefAndUnscopedRef").Parameters[0], "in R x", RefKind.In, ScopedKind.None, expectedHasUnscopedRefAttribute: true);
}
[Fact]
[WorkItem(63529, "https://github.com/dotnet/roslyn/issues/63529")]
public void CallUnscopedRefMethodFromScopedOne()
{
var source =
@"using System;
using System.Diagnostics.CodeAnalysis;
ref struct A
{
void Test()
{
this.GetSpan();
}
[UnscopedRef]
Span<byte> GetSpan() => default;
}
";
var comp = CreateCompilation(new[] { source, UnscopedRefAttributeDefinition }, targetFramework: TargetFramework.Net50, options: TestOptions.ReleaseDll);
comp.VerifyDiagnostics(
);
}
[Theory]
[InlineData(LanguageVersion.CSharp10)]
[InlineData(LanguageVersion.CSharp11)]
public void RefSafetyRulesAttribute_01(LanguageVersion languageVersion)
{
var source =
@"ref struct R
{
}
struct S1
{
void F1() { }
}
readonly struct S2
{
void F2() { }
}
class A
{
static void F3(out int i3) { i3 = 0; }
static void F4(ref R r4) { }
static void F5(in R r5) { }
}";
var comp = CreateCompilation(source, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion));
comp.VerifyDiagnostics();
bool useUpdatedRules = languageVersion == LanguageVersion.CSharp11;
VerifyParameterSymbol(comp.GetMember<MethodSymbol>("S1.F1").ThisParameter, "ref S1 this", RefKind.Ref, ScopedKind.ScopedRef);
VerifyParameterSymbol(comp.GetMember<MethodSymbol>("S2.F2").ThisParameter, "in S2 this", RefKind.In, ScopedKind.ScopedRef);
VerifyParameterSymbol(comp.GetMember<MethodSymbol>("A.F3").Parameters[0], "out System.Int32 i3", RefKind.Out, useUpdatedRules ? ScopedKind.ScopedRef : ScopedKind.None);
VerifyParameterSymbol(comp.GetMember<MethodSymbol>("A.F4").Parameters[0], "ref R r4", RefKind.Ref, ScopedKind.None);
VerifyParameterSymbol(comp.GetMember<MethodSymbol>("A.F5").Parameters[0], "in R r5", RefKind.In, ScopedKind.None);
}
[Theory]
[CombinatorialData]
public void RefSafetyRulesAttribute_02(
[CombinatorialValues(LanguageVersion.CSharp10, LanguageVersion.CSharp11)] LanguageVersion languageVersionA,
[CombinatorialValues(LanguageVersion.CSharp10, LanguageVersion.CSharp11)] LanguageVersion languageVersionB,
bool useCompilationReference)
{
var sourceA =
@"public ref struct R
{
}
public struct S1
{
public void F1() { }
}
public readonly struct S2
{
public void F2() { }
}
public class A
{
public static void F3(out int i3) { i3 = 0; }
public static void F4(ref R r4) { }
public static void F5(in R r5) { }
}";
var comp = CreateCompilation(sourceA, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersionA));
comp.VerifyDiagnostics();
var refA = AsReference(comp, useCompilationReference);
var sourceB =
@"";
comp = CreateCompilation(sourceB, references: new[] { refA }, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersionB));
comp.VerifyDiagnostics();
bool useUpdatedRules = languageVersionA == LanguageVersion.CSharp11;
VerifyParameterSymbol(comp.GetMember<MethodSymbol>("S1.F1").ThisParameter, "ref S1 this", RefKind.Ref, ScopedKind.ScopedRef);
VerifyParameterSymbol(comp.GetMember<MethodSymbol>("S2.F2").ThisParameter, "in S2 this", RefKind.In, ScopedKind.ScopedRef);
VerifyParameterSymbol(comp.GetMember<MethodSymbol>("A.F3").Parameters[0], "out System.Int32 i3", RefKind.Out, useUpdatedRules ? ScopedKind.ScopedRef : ScopedKind.None);
VerifyParameterSymbol(comp.GetMember<MethodSymbol>("A.F4").Parameters[0], "ref R r4", RefKind.Ref, ScopedKind.None);
VerifyParameterSymbol(comp.GetMember<MethodSymbol>("A.F5").Parameters[0], "in R r5", RefKind.In, ScopedKind.None);
}
[Theory]
[InlineData(LanguageVersion.CSharp10)]
[InlineData(LanguageVersion.CSharp11)]
public void RefSafetyRulesAttribute_03(LanguageVersion languageVersion)
{
var source =
@"ref struct R { }
class Program
{
static void Main()
{
var f1 = (out int i1) => { i1 = 0; };
var f2 = (R r2) => { };
var f3 = (ref R r3) => { };
var f4 = (in R r4) => { };
var f5 = (out R r5) => { r5 = default; };
}
}";
var comp = CreateCompilation(source, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion));
comp.VerifyEmitDiagnostics();
var tree = comp.SyntaxTrees[0];
var model = comp.GetSemanticModel(tree);
var delegateTypesAndLambdas = tree.GetRoot().DescendantNodes().OfType<VariableDeclaratorSyntax>().Select(d => getDelegateTypeAndLambda(model, d)).ToArray();
bool useUpdatedRules = languageVersion == LanguageVersion.CSharp11;
verifyParameter(delegateTypesAndLambdas[0], 0, "out System.Int32", "i1", RefKind.Out, useUpdatedRules ? ScopedKind.ScopedRef : ScopedKind.None);
verifyParameter(delegateTypesAndLambdas[1], 0, "R", "r2", RefKind.None, ScopedKind.None);
verifyParameter(delegateTypesAndLambdas[2], 0, "ref R", "r3", RefKind.Ref, ScopedKind.None);
verifyParameter(delegateTypesAndLambdas[3], 0, "in R", "r4", RefKind.In, ScopedKind.None);
verifyParameter(delegateTypesAndLambdas[4], 0, "out R", "r5", RefKind.Out, useUpdatedRules ? ScopedKind.ScopedRef : ScopedKind.None);
static void verifyParameter((NamedTypeSymbol, LambdaSymbol) delegateTypeAndLambda, int parameterIndex, string expectedDisplayType, string expectedDisplayName, RefKind expectedRefKind, ScopedKind expectedScope)
{
var (delegateType, lambda) = delegateTypeAndLambda;
VerifyParameterSymbol(delegateType.DelegateInvokeMethod.Parameters[parameterIndex], $"{expectedDisplayType} arg", expectedRefKind, expectedScope);
VerifyParameterSymbol(lambda.Parameters[parameterIndex], $"{expectedDisplayType} {expectedDisplayName}", expectedRefKind, expectedScope);
}
static (NamedTypeSymbol, LambdaSymbol) getDelegateTypeAndLambda(SemanticModel model, VariableDeclaratorSyntax decl)
{
var delegateType = (NamedTypeSymbol)model.GetDeclaredSymbol(decl).GetSymbol<LocalSymbol>().Type;
var value = decl.DescendantNodes().OfType<ParenthesizedLambdaExpressionSyntax>().Single();
var lambda = model.GetSymbolInfo(value).Symbol.GetSymbol<LambdaSymbol>();
return (delegateType, lambda);
}
}
[Theory]
[CombinatorialData]
public void RefSafetyRulesAttribute_04(
[CombinatorialValues(LanguageVersion.CSharp10, LanguageVersion.CSharp11)] LanguageVersion languageVersionA,
[CombinatorialValues(LanguageVersion.CSharp10, LanguageVersion.CSharp11)] LanguageVersion languageVersionB,
bool useCompilationReference)
{
var sourceA =
@"public ref struct R { }
unsafe public class A
{
public delegate*<out int, void> F1 = null;
public delegate*<R, void> F2 = null;
public delegate*<ref R, void> F3 = null;
public delegate*<in R, void> F4 = null;
public delegate*<out R, void> F5 = null;
}";
var comp = CreateCompilation(sourceA, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersionA), options: TestOptions.UnsafeReleaseDll);
comp.VerifyDiagnostics();
var refA = AsReference(comp, useCompilationReference);
var sourceB =
@"";
comp = CreateCompilation(sourceB, references: new[] { refA }, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersionB));
comp.VerifyDiagnostics();
bool useUpdatedRules = languageVersionA == LanguageVersion.CSharp11;
VerifyParameterSymbol(getFunctionPointerMethod(comp, "A.F1").Parameters[0], "out modreq(System.Runtime.InteropServices.OutAttribute) System.Int32", RefKind.Out, useUpdatedRules ? ScopedKind.ScopedRef : ScopedKind.None);
VerifyParameterSymbol(getFunctionPointerMethod(comp, "A.F2").Parameters[0], "R", RefKind.None, ScopedKind.None);
VerifyParameterSymbol(getFunctionPointerMethod(comp, "A.F3").Parameters[0], "ref R", RefKind.Ref, ScopedKind.None);
VerifyParameterSymbol(getFunctionPointerMethod(comp, "A.F4").Parameters[0], "in modreq(System.Runtime.InteropServices.InAttribute) R", RefKind.In, ScopedKind.None);
VerifyParameterSymbol(getFunctionPointerMethod(comp, "A.F5").Parameters[0], "out modreq(System.Runtime.InteropServices.OutAttribute) R", RefKind.Out, useUpdatedRules ? ScopedKind.ScopedRef : ScopedKind.None);
static MethodSymbol getFunctionPointerMethod(CSharpCompilation comp, string qualifiedName) =>
((FunctionPointerTypeSymbol)comp.GetMember<FieldSymbol>(qualifiedName).Type).Signature;
}
[Theory]
[InlineData(LanguageVersion.CSharp10)]
[InlineData(LanguageVersion.CSharp11)]
public void RefSafetyRulesAttribute_05(LanguageVersion languageVersion)
{
var source =
@"using System.Diagnostics.CodeAnalysis;
ref struct R { }
struct S
{
[UnscopedRef] ref int F() => throw null;
[UnscopedRef] ref int P => throw null;
}
class Program
{
static void F1([UnscopedRef] out int i1) { i1 = 0; }
static void F2([UnscopedRef] R r2) { }
static void F3([UnscopedRef] ref R r3) { }
static void F4([UnscopedRef] in R r4) { }
static void F5([UnscopedRef] out R r5) { }
}";
var comp = CreateCompilation(new[] { source, UnscopedRefAttributeDefinition }, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion));
if (languageVersion == LanguageVersion.CSharp11)
{
comp.VerifyEmitDiagnostics(
// (11,21): error CS9063: UnscopedRefAttribute cannot be applied to this parameter because it is unscoped by default.
// static void F2([UnscopedRef] R r2) { }
Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedTarget, "UnscopedRef").WithLocation(11, 21));
}
else
{
comp.VerifyEmitDiagnostics(
// (10,21): error CS9063: UnscopedRefAttribute cannot be applied to this parameter because it is unscoped by default.
// static void F1([UnscopedRef] out int i1) { i1 = 0; }
Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedTarget, "UnscopedRef").WithLocation(10, 21),
// (11,21): error CS9063: UnscopedRefAttribute cannot be applied to this parameter because it is unscoped by default.
// static void F2([UnscopedRef] R r2) { }
Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedTarget, "UnscopedRef").WithLocation(11, 21),
// (12,21): error CS9063: UnscopedRefAttribute cannot be applied to this parameter because it is unscoped by default.
// static void F3([UnscopedRef] ref R r3) { }
Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedTarget, "UnscopedRef").WithLocation(12, 21),
// (13,21): error CS9063: UnscopedRefAttribute cannot be applied to this parameter because it is unscoped by default.
// static void F4([UnscopedRef] in R r4) { }
Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedTarget, "UnscopedRef").WithLocation(13, 21),
// (14,21): error CS9063: UnscopedRefAttribute cannot be applied to this parameter because it is unscoped by default.
// static void F5([UnscopedRef] out R r5) { }
Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedTarget, "UnscopedRef").WithLocation(14, 21));
}
VerifyParameterSymbol(comp.GetMember<MethodSymbol>("S.F").ThisParameter, "ref S this", RefKind.Ref, ScopedKind.None, expectedHasUnscopedRefAttribute: true);
VerifyParameterSymbol(comp.GetMember<PropertySymbol>("S.P").GetMethod.ThisParameter, "ref S this", RefKind.Ref, ScopedKind.None, expectedHasUnscopedRefAttribute: true);
VerifyParameterSymbol(comp.GetMember<MethodSymbol>("Program.F1").Parameters[0], "out System.Int32 i1", RefKind.Out, ScopedKind.None, expectedHasUnscopedRefAttribute: true);
VerifyParameterSymbol(comp.GetMember<MethodSymbol>("Program.F2").Parameters[0], "R r2", RefKind.None, ScopedKind.None, expectedHasUnscopedRefAttribute: true);
VerifyParameterSymbol(comp.GetMember<MethodSymbol>("Program.F3").Parameters[0], "ref R r3", RefKind.Ref, ScopedKind.None, expectedHasUnscopedRefAttribute: true);
VerifyParameterSymbol(comp.GetMember<MethodSymbol>("Program.F4").Parameters[0], "in R r4", RefKind.In, ScopedKind.None, expectedHasUnscopedRefAttribute: true);
VerifyParameterSymbol(comp.GetMember<MethodSymbol>("Program.F5").Parameters[0], "out R r5", RefKind.Out, ScopedKind.None, expectedHasUnscopedRefAttribute: true);
}
[Theory]
[CombinatorialData]
public void RefSafetyRulesAttribute_06(
[CombinatorialValues(LanguageVersion.CSharp10, LanguageVersion.CSharp11)] LanguageVersion languageVersionA,
[CombinatorialValues(LanguageVersion.CSharp10, LanguageVersion.CSharp11)] LanguageVersion languageVersionB,
bool useCompilationReference)
{
var sourceA =
@"public ref struct R<T>
{
}
public abstract class A<T>
{
public abstract ref T F1(out T t1);
public abstract ref T F2(R<T> r2);
public abstract ref T F3(ref R<T> r3);
public abstract ref T F4(in R<T> r4);
public abstract ref T F5(out R<T> r5);
}";
var comp = CreateCompilation(sourceA, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersionA));
comp.VerifyEmitDiagnostics();
var refA = AsReference(comp, useCompilationReference);
var sourceB =
@"class B : A<int>
{
public override ref int F1(out int i1) => throw null; // 1
public override ref int F2(R<int> r2) => throw null;
public override ref int F3(ref R<int> r3) => throw null;
public override ref int F4(in R<int> r4) => throw null;
public override ref int F5(out R<int> r5) => throw null; // 2
}";
comp = CreateCompilation(sourceB, references: new[] { refA }, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersionB));
if (languageVersionA == LanguageVersion.CSharp11 &&
languageVersionB == LanguageVersion.CSharp10)
{
comp.VerifyEmitDiagnostics(
// (3,29): warning CS9074: The 'scoped' modifier of parameter 'i1' doesn't match overridden or implemented member.
// public override ref int F1(out int i1) => throw null; // 1
Diagnostic(ErrorCode.WRN_ScopedMismatchInParameterOfOverrideOrImplementation, "F1").WithArguments("i1").WithLocation(3, 29),
// (7,29): warning CS9074: The 'scoped' modifier of parameter 'r5' doesn't match overridden or implemented member.
// public override ref int F5(out R<int> r5) => throw null; // 2
Diagnostic(ErrorCode.WRN_ScopedMismatchInParameterOfOverrideOrImplementation, "F5").WithArguments("r5").WithLocation(7, 29));
}
else
{
comp.VerifyEmitDiagnostics();
}
}
[Theory]
[CombinatorialData]
public void RefSafetyRulesAttribute_07(
[CombinatorialValues(LanguageVersion.CSharp10, LanguageVersion.CSharp11)] LanguageVersion languageVersionA,
[CombinatorialValues(LanguageVersion.CSharp10, LanguageVersion.CSharp11)] LanguageVersion languageVersionB,
bool useCompilationReference)
{
var sourceA =
@"public ref struct R<T>
{
}
public interface I<T>
{
ref readonly T F1(out T t1);
ref readonly T F2(R<T> r2);
ref readonly T F3(ref R<T> r3);
ref readonly T F4(in R<T> r4);
ref readonly T F5(out R<T> r5);
}";
var comp = CreateCompilation(sourceA, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersionA));
comp.VerifyEmitDiagnostics();
var refA = AsReference(comp, useCompilationReference);
var sourceB =
@"class B1 : I<int>
{
public ref readonly int F1(out int i1) => throw null; // 1
public ref readonly int F2(R<int> r2) => throw null;
public ref readonly int F3(ref R<int> r3) => throw null;
public ref readonly int F4(in R<int> r4) => throw null;
public ref readonly int F5(out R<int> r5) => throw null; // 2
}
class B2 : I<object>
{
ref readonly object I<object>.F1(out object o1) => throw null; // 3
ref readonly object I<object>.F2(R<object> r2) => throw null;
ref readonly object I<object>.F3(ref R<object> r3) => throw null;
ref readonly object I<object>.F4(in R<object> r4) => throw null;
ref readonly object I<object>.F5(out R<object> r5) => throw null; // 4
}";
comp = CreateCompilation(sourceB, references: new[] { refA }, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersionB));
if (languageVersionA == LanguageVersion.CSharp11 &&
languageVersionB == LanguageVersion.CSharp10)
{
comp.VerifyEmitDiagnostics(
// (3,29): warning CS9074: The 'scoped' modifier of parameter 'i1' doesn't match overridden or implemented member.
// public ref readonly int F1(out int i1) => throw null; // 1
Diagnostic(ErrorCode.WRN_ScopedMismatchInParameterOfOverrideOrImplementation, "F1").WithArguments("i1").WithLocation(3, 29),
// (7,29): warning CS9074: The 'scoped' modifier of parameter 'r5' doesn't match overridden or implemented member.
// public ref readonly int F5(out R<int> r5) => throw null; // 2
Diagnostic(ErrorCode.WRN_ScopedMismatchInParameterOfOverrideOrImplementation, "F5").WithArguments("r5").WithLocation(7, 29),
// (11,35): warning CS9074: The 'scoped' modifier of parameter 'o1' doesn't match overridden or implemented member.
// ref readonly object I<object>.F1(out object o1) => throw null; // 3
Diagnostic(ErrorCode.WRN_ScopedMismatchInParameterOfOverrideOrImplementation, "F1").WithArguments("o1").WithLocation(11, 35),
// (15,35): warning CS9074: The 'scoped' modifier of parameter 'r5' doesn't match overridden or implemented member.
// ref readonly object I<object>.F5(out R<object> r5) => throw null; // 4
Diagnostic(ErrorCode.WRN_ScopedMismatchInParameterOfOverrideOrImplementation, "F5").WithArguments("r5").WithLocation(15, 35));
}
else
{
comp.VerifyEmitDiagnostics();
}
}
[Theory]
[CombinatorialData]
public void RefSafetyRulesAttribute_08(bool useCompilationReference)
{
var sourceA =
@"using System.Diagnostics.CodeAnalysis;
public ref struct R<T> { }
public abstract class A<T>
{
public abstract void F1([UnscopedRef] out T t1);
public abstract void F2(ref R<T> r2);
public abstract void F3(in R<T> r3);
}";
var comp = CreateCompilation(new[] { sourceA, UnscopedRefAttributeDefinition });
comp.VerifyEmitDiagnostics();
var refA = AsReference(comp, useCompilationReference);
var sourceB =
@"class B : A<int>
{
public override void F1(out int i1) { i1 = 0; }
public override void F2(scoped ref R<int> r3) { }
public override void F3(scoped in R<int> r4) { }
}";
comp = CreateCompilation(sourceB, references: new[] { refA });
comp.VerifyEmitDiagnostics();
}
[Theory]
[CombinatorialData]
public void RefSafetyRulesAttribute_09(
[CombinatorialValues(LanguageVersion.CSharp10, LanguageVersion.CSharp11)] LanguageVersion languageVersionB,
bool useCompilationReference)
{
var sourceA =
@"using System.Diagnostics.CodeAnalysis;
public ref struct R<T> { }
public interface I<T>
{
void F1([UnscopedRef] out T t1);
void F2(ref R<T> r2);
void F3(in R<T> r3);
}";
var comp = CreateCompilation(new[] { sourceA, UnscopedRefAttributeDefinition });
comp.VerifyEmitDiagnostics();
var refA = AsReference(comp, useCompilationReference);
var sourceB =
@"class B1 : I<int>
{
public void F1(out int i1) { i1 = 0; }
public void F2(ref R<int> r2) { }
public void F3(in R<int> r3) { }
}
class B2 : I<object>
{
void I<object>.F1(out object o1) { o1 = null; }
void I<object>.F2(ref R<object> r2) { }
void I<object>.F3(in R<object> r3) { }
}";
comp = CreateCompilation(sourceB, references: new[] { refA }, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersionB));
comp.VerifyEmitDiagnostics();
}
[Theory]
[CombinatorialData]
public void RefSafetyRulesAttribute_10(
[CombinatorialValues(LanguageVersion.CSharp10, LanguageVersion.CSharp11)] LanguageVersion languageVersionA,
[CombinatorialValues(LanguageVersion.CSharp10, LanguageVersion.CSharp11)] LanguageVersion languageVersionB,
bool useCompilationReference)
{
var sourceA =
@"public ref struct R<T>
{
}
public delegate ref T D1<T>(out T t1);
public delegate ref T D2<T>(R<T> r2);
public delegate ref T D3<T>(ref R<T> r3);
public delegate ref T D4<T>(in R<T> r4);
public delegate ref T D5<T>(out R<T> r5);
";
var comp = CreateCompilation(sourceA, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersionA));
comp.VerifyEmitDiagnostics();
var refA = AsReference(comp, useCompilationReference);
var sourceB =
@"class Program
{
static ref int F1(out int i1) => throw null;
static ref int F2(R<int> r2) => throw null;
static ref int F3(ref R<int> r3) => throw null;
static ref int F4(in R<int> r4) => throw null;
static ref int F5(out R<int> r5) => throw null;
static void Main()
{
D1<int> d1 = F1; // 1
D2<int> d2 = F2;
D3<int> d3 = F3;
D4<int> d4 = F4;
D5<int> d5 = F5; // 2
}
}";
comp = CreateCompilation(sourceB, references: new[] { refA }, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersionB));
if (languageVersionA == LanguageVersion.CSharp11 &&
languageVersionB == LanguageVersion.CSharp10)
{
comp.VerifyEmitDiagnostics(
// (10,22): warning CS9073: The 'scoped' modifier of parameter 'i1' doesn't match target 'D1<int>'.
// D1<int> d1 = F1; // 1
Diagnostic(ErrorCode.WRN_ScopedMismatchInParameterOfTarget, "F1").WithArguments("i1", "D1<int>").WithLocation(10, 22),
// (14,22): warning CS9073: The 'scoped' modifier of parameter 'r5' doesn't match target 'D5<int>'.
// D5<int> d5 = F5; // 2
Diagnostic(ErrorCode.WRN_ScopedMismatchInParameterOfTarget, "F5").WithArguments("r5", "D5<int>").WithLocation(14, 22));
}
else
{
comp.VerifyEmitDiagnostics();
}
}
[WorkItem(63761, "https://github.com/dotnet/roslyn/issues/63761")]
[Theory]
[CombinatorialData]
public void RefSafetyRulesAttribute_11(bool useCompilationReference)
{
var sourceA =
@"public ref struct R<T>
{
}
public abstract class A<T>
{
public abstract ref readonly T F1(out T t);
}
public interface I<T>
{
ref T F2(out T t);
}
public delegate ref T D3<T>(out T t);
";
var comp = CreateCompilation(sourceA, parseOptions: TestOptions.Regular);
comp.VerifyEmitDiagnostics();
var refA = AsReference(comp, useCompilationReference);
var sourceB1 =
@"class B : A<int>, I<string>
{
public override ref readonly int F1(out int i) => throw null; // 1
ref string I<string>.F2(out string s) => throw null; // 2
}
class Program
{
static ref object F3(out object o) => throw null;
static void Main()
{
D3<object> d3 = F3; // 3
}
}";
comp = CreateCompilation(sourceB1, references: new[] { refA }, parseOptions: TestOptions.Regular10);
comp.VerifyEmitDiagnostics(
// (3,38): warning CS9074: The 'scoped' modifier of parameter 'i' doesn't match overridden or implemented member.
// public override ref readonly int F1(out int i) => throw null; // 1
Diagnostic(ErrorCode.WRN_ScopedMismatchInParameterOfOverrideOrImplementation, "F1").WithArguments("i").WithLocation(3, 38),
// (4,26): warning CS9074: The 'scoped' modifier of parameter 's' doesn't match overridden or implemented member.
// ref string I<string>.F2(out string s) => throw null; // 2
Diagnostic(ErrorCode.WRN_ScopedMismatchInParameterOfOverrideOrImplementation, "F2").WithArguments("s").WithLocation(4, 26),
// (11,25): warning CS9073: The 'scoped' modifier of parameter 'o' doesn't match target 'D3<object>'.
// D3<object> d3 = F3; // 3
Diagnostic(ErrorCode.WRN_ScopedMismatchInParameterOfTarget, "F3").WithArguments("o", "D3<object>").WithLocation(11, 25));
var sourceB2 =
@"using System.Diagnostics.CodeAnalysis;
class B : A<int>, I<string>
{
public override ref readonly int F1([UnscopedRef] out int i) => throw null; // 1
ref string I<string>.F2([UnscopedRef] out string s) => throw null; // 2
}
class Program
{
static ref object F3([UnscopedRef] out object o) => throw null;
static void Main()
{
D3<object> d3 = F3; // 3
}
}";
comp = CreateCompilation(new[] { sourceB2, UnscopedRefAttributeDefinition }, references: new[] { refA }, parseOptions: TestOptions.Regular);
comp.VerifyEmitDiagnostics(
// (4,38): error CS8987: The 'scoped' modifier of parameter 'i' doesn't match overridden or implemented member.
// public override ref readonly int F1([UnscopedRef] out int i) => throw null; // 1
Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfOverrideOrImplementation, "F1").WithArguments("i").WithLocation(4, 38),
// (5,26): error CS8987: The 'scoped' modifier of parameter 's' doesn't match overridden or implemented member.
// ref string I<string>.F2([UnscopedRef] out string s) => throw null; // 2
Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfOverrideOrImplementation, "F2").WithArguments("s").WithLocation(5, 26),
// (12,25): error CS8986: The 'scoped' modifier of parameter 'o' doesn't match target 'D3<object>'.
// D3<object> d3 = F3; // 3
Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "F3").WithArguments("o", "D3<object>").WithLocation(12, 25));
}
[Theory]
[CombinatorialData]
public void RefSafetyRulesAttribute_12(
[CombinatorialValues(LanguageVersion.CSharp10, LanguageVersion.CSharp11)] LanguageVersion languageVersionB,
bool useCompilationReference)
{
var sourceA =
@"public ref struct R<T>
{
}
public abstract class A<T>
{
public abstract ref readonly T F1(scoped R<T> r);
}
public interface I<T>
{
ref T F2(scoped R<T> r);
}
public delegate ref T D3<T>(scoped R<T> r);
";
var comp = CreateCompilation(sourceA, parseOptions: TestOptions.Regular);
comp.VerifyEmitDiagnostics();
var refA = AsReference(comp, useCompilationReference);
var sourceB =
@"class B : A<int>, I<string>
{
public override ref readonly int F1(R<int> r) => throw null; // 1
ref string I<string>.F2(R<string> r) => throw null; // 2
}
class Program
{
static ref object F3(R<object> r) => throw null;
static void Main()
{
D3<object> d3 = F3; // 3
}
}";
comp = CreateCompilation(sourceB, references: new[] { refA }, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersionB));
if (languageVersionB == LanguageVersion.CSharp10)
{
comp.VerifyEmitDiagnostics(
// (3,38): warning CS9074: The 'scoped' modifier of parameter 'r' doesn't match overridden or implemented member.
// public override ref readonly int F1(R<int> r) => throw null; // 1
Diagnostic(ErrorCode.WRN_ScopedMismatchInParameterOfOverrideOrImplementation, "F1").WithArguments("r").WithLocation(3, 38),
// (4,26): warning CS9074: The 'scoped' modifier of parameter 'r' doesn't match overridden or implemented member.
// ref string I<string>.F2(R<string> r) => throw null; // 2
Diagnostic(ErrorCode.WRN_ScopedMismatchInParameterOfOverrideOrImplementation, "F2").WithArguments("r").WithLocation(4, 26),
// (11,25): warning CS9073: The 'scoped' modifier of parameter 'r' doesn't match target 'D3<object>'.
// D3<object> d3 = F3; // 3
Diagnostic(ErrorCode.WRN_ScopedMismatchInParameterOfTarget, "F3").WithArguments("r", "D3<object>").WithLocation(11, 25));
}
else
{
comp.VerifyEmitDiagnostics(
// (3,38): error CS8987: The 'scoped' modifier of parameter 'r' doesn't match overridden or implemented member.
// public override ref readonly int F1(R<int> r) => throw null; // 1
Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfOverrideOrImplementation, "F1").WithArguments("r").WithLocation(3, 38),
// (4,26): error CS8987: The 'scoped' modifier of parameter 'r' doesn't match overridden or implemented member.
// ref string I<string>.F2(R<string> r) => throw null; // 2
Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfOverrideOrImplementation, "F2").WithArguments("r").WithLocation(4, 26),
// (11,25): error CS8986: The 'scoped' modifier of parameter 'r' doesn't match target 'D3<object>'.
// D3<object> d3 = F3; // 3
Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "F3").WithArguments("r", "D3<object>").WithLocation(11, 25));
}
}
[Theory]
[CombinatorialData]
public void UnscopedRefAttribute_Overrides_04(
[CombinatorialValues(LanguageVersion.CSharp10, LanguageVersion.CSharp11)] LanguageVersion languageVersionA,
bool useCompilationReference)
{
var sourceA =
@"public abstract class A<T>
{
public abstract ref readonly T F1(ref T t);
public abstract ref readonly T F2(in T t);
public abstract ref readonly T F3(out T t);
}
public interface I<T>
{
ref T F1(ref T t);
ref T F2(in T t);
ref T F3(out T t);
}
public delegate ref T D2<T>(ref T t);
public delegate ref T D3<T>(in T t);
public delegate ref T D4<T>(out T t);
";
var comp = CreateCompilation(sourceA, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersionA));
comp.VerifyEmitDiagnostics();
var refA = AsReference(comp, useCompilationReference);
var sourceB =
@"using System.Diagnostics.CodeAnalysis;
class B : A<int>, I<string>
{
public override ref readonly int F1([UnscopedRef] ref int i) => throw null; // 1
public override ref readonly int F2([UnscopedRef] in int i) => throw null; // 2
public override ref readonly int F3([UnscopedRef] out int i) => throw null; // 3
ref string I<string>.F1([UnscopedRef] ref string s) => throw null; // 4
ref string I<string>.F2([UnscopedRef] in string s) => throw null; // 5
ref string I<string>.F3([UnscopedRef] out string s) => throw null; // 6
}
class Program
{
static ref object F1([UnscopedRef] ref object o) => throw null;
static ref object F2([UnscopedRef] in object o) => throw null;
static ref object F3([UnscopedRef] out object o) => throw null;
static void Main()
{
D2<object> d1 = F1; // 7
D3<object> d2 = F2; // 8
D4<object> d3 = F3; // 9
}
}";
comp = CreateCompilation(new[] { sourceB, UnscopedRefAttributeDefinition }, references: new[] { refA });
if (languageVersionA == LanguageVersion.CSharp10)
{
comp.VerifyEmitDiagnostics(
// (4,38): warning CS9074: The 'scoped' modifier of parameter 'i' doesn't match overridden or implemented member.
// public override ref readonly int F1([UnscopedRef] ref int i) => throw null; // 1
Diagnostic(ErrorCode.WRN_ScopedMismatchInParameterOfOverrideOrImplementation, "F1").WithArguments("i").WithLocation(4, 38),
// (5,38): warning CS9074: The 'scoped' modifier of parameter 'i' doesn't match overridden or implemented member.
// public override ref readonly int F2([UnscopedRef] in int i) => throw null; // 2
Diagnostic(ErrorCode.WRN_ScopedMismatchInParameterOfOverrideOrImplementation, "F2").WithArguments("i").WithLocation(5, 38),
// (6,38): warning CS9074: The 'scoped' modifier of parameter 'i' doesn't match overridden or implemented member.
// public override ref readonly int F3([UnscopedRef] out int i) => throw null; // 3
Diagnostic(ErrorCode.WRN_ScopedMismatchInParameterOfOverrideOrImplementation, "F3").WithArguments("i").WithLocation(6, 38),
// (7,26): warning CS9074: The 'scoped' modifier of parameter 's' doesn't match overridden or implemented member.
// ref string I<string>.F1([UnscopedRef] ref string s) => throw null; // 4
Diagnostic(ErrorCode.WRN_ScopedMismatchInParameterOfOverrideOrImplementation, "F1").WithArguments("s").WithLocation(7, 26),
// (8,26): warning CS9074: The 'scoped' modifier of parameter 's' doesn't match overridden or implemented member.
// ref string I<string>.F2([UnscopedRef] in string s) => throw null; // 5
Diagnostic(ErrorCode.WRN_ScopedMismatchInParameterOfOverrideOrImplementation, "F2").WithArguments("s").WithLocation(8, 26),
// (9,26): warning CS9074: The 'scoped' modifier of parameter 's' doesn't match overridden or implemented member.
// ref string I<string>.F3([UnscopedRef] out string s) => throw null; // 6
Diagnostic(ErrorCode.WRN_ScopedMismatchInParameterOfOverrideOrImplementation, "F3").WithArguments("s").WithLocation(9, 26),
// (18,25): warning CS9073: The 'scoped' modifier of parameter 'o' doesn't match target 'D2<object>'.
// D2<object> d1 = F1; // 7
Diagnostic(ErrorCode.WRN_ScopedMismatchInParameterOfTarget, "F1").WithArguments("o", "D2<object>").WithLocation(18, 25),
// (19,25): warning CS9073: The 'scoped' modifier of parameter 'o' doesn't match target 'D3<object>'.
// D3<object> d2 = F2; // 8
Diagnostic(ErrorCode.WRN_ScopedMismatchInParameterOfTarget, "F2").WithArguments("o", "D3<object>").WithLocation(19, 25),
// (20,25): warning CS9073: The 'scoped' modifier of parameter 'o' doesn't match target 'D4<object>'.
// D4<object> d3 = F3; // 9
Diagnostic(ErrorCode.WRN_ScopedMismatchInParameterOfTarget, "F3").WithArguments("o", "D4<object>").WithLocation(20, 25));
}
else
{
comp.VerifyEmitDiagnostics(
// (4,38): error CS8987: The 'scoped' modifier of parameter 'i' doesn't match overridden or implemented member.
// public override ref readonly int F1([UnscopedRef] ref int i) => throw null; // 1
Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfOverrideOrImplementation, "F1").WithArguments("i").WithLocation(4, 38),
// (5,38): error CS8987: The 'scoped' modifier of parameter 'i' doesn't match overridden or implemented member.
// public override ref readonly int F2([UnscopedRef] in int i) => throw null; // 2
Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfOverrideOrImplementation, "F2").WithArguments("i").WithLocation(5, 38),
// (6,38): error CS8987: The 'scoped' modifier of parameter 'i' doesn't match overridden or implemented member.
// public override ref readonly int F3([UnscopedRef] out int i) => throw null; // 3
Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfOverrideOrImplementation, "F3").WithArguments("i").WithLocation(6, 38),
// (7,26): error CS8987: The 'scoped' modifier of parameter 's' doesn't match overridden or implemented member.
// ref string I<string>.F1([UnscopedRef] ref string s) => throw null; // 4
Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfOverrideOrImplementation, "F1").WithArguments("s").WithLocation(7, 26),
// (8,26): error CS8987: The 'scoped' modifier of parameter 's' doesn't match overridden or implemented member.
// ref string I<string>.F2([UnscopedRef] in string s) => throw null; // 5
Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfOverrideOrImplementation, "F2").WithArguments("s").WithLocation(8, 26),
// (9,26): error CS8987: The 'scoped' modifier of parameter 's' doesn't match overridden or implemented member.
// ref string I<string>.F3([UnscopedRef] out string s) => throw null; // 6
Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfOverrideOrImplementation, "F3").WithArguments("s").WithLocation(9, 26),
// (18,25): error CS8986: The 'scoped' modifier of parameter 'o' doesn't match target 'D2<object>'.
// D2<object> d1 = F1; // 7
Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "F1").WithArguments("o", "D2<object>").WithLocation(18, 25),
// (19,25): error CS8986: The 'scoped' modifier of parameter 'o' doesn't match target 'D3<object>'.
// D3<object> d2 = F2; // 8
Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "F2").WithArguments("o", "D3<object>").WithLocation(19, 25),
// (20,25): error CS8986: The 'scoped' modifier of parameter 'o' doesn't match target 'D4<object>'.
// D4<object> d3 = F3; // 9
Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "F3").WithArguments("o", "D4<object>").WithLocation(20, 25));
}
}
[Theory]
[CombinatorialData]
public void UnscopedRefAttribute_Overrides_05(
[CombinatorialValues(LanguageVersion.CSharp10, LanguageVersion.CSharp11)] LanguageVersion languageVersionB,
bool useCompilationReference)
{
var sourceA =
@"using System.Diagnostics.CodeAnalysis;
public abstract class A<T>
{
public abstract ref readonly T F1([UnscopedRef] ref T t);
public abstract ref readonly T F2([UnscopedRef] in T t);
public abstract ref readonly T F3([UnscopedRef] out T t);
}
public interface I<T>
{
ref T F1([UnscopedRef] ref T t);
ref T F2([UnscopedRef] in T t);
ref T F3([UnscopedRef] out T t);
}
public delegate ref T D2<T>([UnscopedRef] ref T t);
public delegate ref T D3<T>([UnscopedRef] in T t);
public delegate ref T D4<T>([UnscopedRef] out T t);
";
var comp = CreateCompilation(new[] { sourceA, UnscopedRefAttributeDefinition }, parseOptions: TestOptions.Regular);
comp.VerifyEmitDiagnostics();
var refA = AsReference(comp, useCompilationReference);
var sourceB =
@"class B : A<int>, I<string>
{
public override ref readonly int F1(ref int i) => throw null;
public override ref readonly int F2(in int i) => throw null;
public override ref readonly int F3(out int i) => throw null;
ref string I<string>.F1(ref string s) => throw null;
ref string I<string>.F2(in string s) => throw null;
ref string I<string>.F3(out string s) => throw null;
}
class Program
{
static ref object F1(ref object o) => throw null;
static ref object F2(in object o) => throw null;
static ref object F3(out object o) => throw null;
static void Main()
{
D2<object> d1 = F1;
D3<object> d2 = F2;
D4<object> d3 = F3;
}
}";
comp = CreateCompilation(sourceB, references: new[] { refA }, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersionB));
comp.VerifyEmitDiagnostics();
}
[Theory]
[CombinatorialData]
public void UnscopedRefAttribute_Overrides_06(
[CombinatorialValues(LanguageVersion.CSharp10, LanguageVersion.CSharp11)] LanguageVersion languageVersionB,
bool useCompilationReference)
{
var sourceA =
@"using System.Diagnostics.CodeAnalysis;
public ref struct R { }
public class A
{
public static void F1(ref R x, ref R y) { }
public static void F2([UnscopedRef] ref R x, ref R y) { }
public static void F3(in R x, ref R y) { }
public static void F4([UnscopedRef] in R x, ref R y) { }
}
";
var comp = CreateCompilation(new[] { sourceA, UnscopedRefAttributeDefinition });
comp.VerifyEmitDiagnostics();
verifyParameters(comp.GetMember<NamedTypeSymbol>("A"));
var refA = AsReference(comp, useCompilationReference);
var sourceB =
@"class B
{
static void F1(ref R x, ref R y)
{
A.F1(ref x, ref y);
}
static void F2(ref R x, ref R y)
{
A.F2(ref x, ref y); // 1
}
static void F3(in R x, ref R y)
{
A.F3(in x, ref y);
}
static void F4(in R x, ref R y)
{
A.F4(in x, ref y); // 2
}
}";
comp = CreateCompilation(sourceB, new[] { refA }, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersionB));
comp.VerifyEmitDiagnostics(
// (9,9): error CS8350: This combination of arguments to 'A.F2(ref R, ref R)' is disallowed because it may expose variables referenced by parameter 'x' outside of their declaration scope
// A.F2(ref x, ref y); // 1
Diagnostic(ErrorCode.ERR_CallArgMixing, "A.F2(ref x, ref y)").WithArguments("A.F2(ref R, ref R)", "x").WithLocation(9, 9),
// (9,18): error CS9077: Cannot return a parameter by reference 'x' through a ref parameter; it can only be returned in a return statement
// A.F2(ref x, ref y); // 1
Diagnostic(ErrorCode.ERR_RefReturnOnlyParameter, "x").WithArguments("x").WithLocation(9, 18),
// (17,9): error CS8350: This combination of arguments to 'A.F4(in R, ref R)' is disallowed because it may expose variables referenced by parameter 'x' outside of their declaration scope
// A.F4(in x, ref y); // 2
Diagnostic(ErrorCode.ERR_CallArgMixing, "A.F4(in x, ref y)").WithArguments("A.F4(in R, ref R)", "x").WithLocation(17, 9),
// (17,17): error CS9077: Cannot return a parameter by reference 'x' through a ref parameter; it can only be returned in a return statement
// A.F4(in x, ref y); // 2
Diagnostic(ErrorCode.ERR_RefReturnOnlyParameter, "x").WithArguments("x").WithLocation(17, 17));
static void verifyParameters(NamedTypeSymbol typeA)
{
VerifyParameterSymbol(typeA.GetMethod("F1").Parameters[0], "ref R x", RefKind.Ref, ScopedKind.None, expectedHasUnscopedRefAttribute: false);
VerifyParameterSymbol(typeA.GetMethod("F2").Parameters[0], "ref R x", RefKind.Ref, ScopedKind.None, expectedHasUnscopedRefAttribute: true);
VerifyParameterSymbol(typeA.GetMethod("F3").Parameters[0], "in R x", RefKind.In, ScopedKind.None, expectedHasUnscopedRefAttribute: false);
VerifyParameterSymbol(typeA.GetMethod("F4").Parameters[0], "in R x", RefKind.In, ScopedKind.None, expectedHasUnscopedRefAttribute: true);
}
}
[Fact]
[WorkItem(64508, "https://github.com/dotnet/roslyn/issues/64508")]
public void UnscopedRefAttribute_InterfaceImplementation_01()
{
string source = """
using System.Diagnostics.CodeAnalysis;
ref struct R<T>
{
public R(ref T t) { }
}
interface I<T>
{
ref T F1();
void F2();
void F3(out R<T> r);
ref T P { get; }
}
struct S1 : I<int>
{
public ref int F1() => throw null;
public void F2() { }
public void F3(out R<int> r) { r = default; }
public ref int P => throw null;
}
struct S2 : I<int>
{
private int _f2;
[UnscopedRef] public ref int F1() => ref _f2; // 1
[UnscopedRef] public void F2() { } // 2
[UnscopedRef] public void F3(out R<int> r) { r = new R<int>(ref _f2); } // 3
[UnscopedRef] public ref int P => ref _f2; // 4
}
struct S3 : I<int>
{
ref int I<int>.F1() => throw null;
void I<int>.F2() { }
void I<int>.F3(out R<int> r) { r = default; }
ref int I<int>.P => throw null;
}
struct S4 : I<int>
{
private int _f4;
[UnscopedRef] ref int I<int>.F1() => ref _f4; // 5
[UnscopedRef] void I<int>.F2() { } // 6
[UnscopedRef] void I<int>.F3(out R<int> r) { r = new R<int>(ref _f4); } // 7
[UnscopedRef] ref int I<int>.P => ref _f4; // 8
}
""";
var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70);
comp.VerifyEmitDiagnostics(
// (23,34): error CS9102: UnscopedRefAttribute cannot be applied to an interface implementation.
// [UnscopedRef] public ref int F1() => ref _f2; // 1
Diagnostic(ErrorCode.ERR_UnscopedRefAttributeInterfaceImplementation, "F1").WithLocation(23, 34),
// (24,31): error CS9102: UnscopedRefAttribute cannot be applied to an interface implementation.
// [UnscopedRef] public void F2() { } // 2
Diagnostic(ErrorCode.ERR_UnscopedRefAttributeInterfaceImplementation, "F2").WithLocation(24, 31),
// (25,31): error CS9102: UnscopedRefAttribute cannot be applied to an interface implementation.
// [UnscopedRef] public void F3(out R<int> r) { r = new R<int>(ref _f2); } // 3
Diagnostic(ErrorCode.ERR_UnscopedRefAttributeInterfaceImplementation, "F3").WithLocation(25, 31),
// (26,39): error CS9102: UnscopedRefAttribute cannot be applied to an interface implementation.
// [UnscopedRef] public ref int P => ref _f2; // 4
Diagnostic(ErrorCode.ERR_UnscopedRefAttributeInterfaceImplementation, "ref _f2").WithLocation(26, 39),
// (38,34): error CS9102: UnscopedRefAttribute cannot be applied to an interface implementation.
// [UnscopedRef] ref int I<int>.F1() => ref _f4; // 5
Diagnostic(ErrorCode.ERR_UnscopedRefAttributeInterfaceImplementation, "F1").WithLocation(38, 34),
// (39,31): error CS9102: UnscopedRefAttribute cannot be applied to an interface implementation.
// [UnscopedRef] void I<int>.F2() { } // 6
Diagnostic(ErrorCode.ERR_UnscopedRefAttributeInterfaceImplementation, "F2").WithLocation(39, 31),
// (40,31): error CS9102: UnscopedRefAttribute cannot be applied to an interface implementation.
// [UnscopedRef] void I<int>.F3(out R<int> r) { r = new R<int>(ref _f4); } // 7
Diagnostic(ErrorCode.ERR_UnscopedRefAttributeInterfaceImplementation, "F3").WithLocation(40, 31),
// (41,39): error CS9102: UnscopedRefAttribute cannot be applied to an interface implementation.
// [UnscopedRef] ref int I<int>.P => ref _f4; // 8
Diagnostic(ErrorCode.ERR_UnscopedRefAttributeInterfaceImplementation, "ref _f4").WithLocation(41, 39));
}
// As above, but interface members are also marked [UnscopedRef].
[Fact]
[WorkItem(64508, "https://github.com/dotnet/roslyn/issues/64508")]
public void UnscopedRefAttribute_InterfaceImplementation_02()
{
string source = """
using System.Diagnostics.CodeAnalysis;
ref struct R<T>
{
public R(ref T t) { }
}
interface I<T>
{
[UnscopedRef] ref T F1(); // 1
[UnscopedRef] void F2(); // 2
[UnscopedRef] void F3(out R<T> r); // 3
[UnscopedRef] ref T P { get; } // 4
}
struct S1 : I<int>
{
public ref int F1() => throw null;
public void F2() { }
public void F3(out R<int> r) { r = default; }
public ref int P => throw null;
}
struct S2 : I<int>
{
private int _f2;
[UnscopedRef] public ref int F1() => ref _f2; // 5
[UnscopedRef] public void F2() { } // 6
[UnscopedRef] public void F3(out R<int> r) { r = new R<int>(ref _f2); } // 7
[UnscopedRef] public ref int P => ref _f2; // 8
}
struct S3 : I<int>
{
ref int I<int>.F1() => throw null;
void I<int>.F2() { }
void I<int>.F3(out R<int> r) { r = default; }
ref int I<int>.P => throw null;
}
struct S4 : I<int>
{
private int _f4;
[UnscopedRef] ref int I<int>.F1() => ref _f4; // 9
[UnscopedRef] void I<int>.F2() { } // 10
[UnscopedRef] void I<int>.F3(out R<int> r) { r = new R<int>(ref _f4); } // 11
[UnscopedRef] ref int I<int>.P => ref _f4; // 12
}
""";
var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70);
comp.VerifyEmitDiagnostics(
// (8,6): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members.
// [UnscopedRef] ref T F1(); // 1
Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(8, 6),
// (9,6): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members.
// [UnscopedRef] void F2(); // 2
Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(9, 6),
// (10,6): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members.
// [UnscopedRef] void F3(out R<T> r); // 3
Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(10, 6),
// (11,6): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members.
// [UnscopedRef] ref T P { get; } // 4
Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(11, 6),
// (23,34): error CS9102: UnscopedRefAttribute cannot be applied to an interface implementation.
// [UnscopedRef] public ref int F1() => ref _f2; // 5
Diagnostic(ErrorCode.ERR_UnscopedRefAttributeInterfaceImplementation, "F1").WithLocation(23, 34),
// (24,31): error CS9102: UnscopedRefAttribute cannot be applied to an interface implementation.
// [UnscopedRef] public void F2() { } // 6
Diagnostic(ErrorCode.ERR_UnscopedRefAttributeInterfaceImplementation, "F2").WithLocation(24, 31),
// (25,31): error CS9102: UnscopedRefAttribute cannot be applied to an interface implementation.
// [UnscopedRef] public void F3(out R<int> r) { r = new R<int>(ref _f2); } // 7
Diagnostic(ErrorCode.ERR_UnscopedRefAttributeInterfaceImplementation, "F3").WithLocation(25, 31),
// (26,39): error CS9102: UnscopedRefAttribute cannot be applied to an interface implementation.
// [UnscopedRef] public ref int P => ref _f2; // 8
Diagnostic(ErrorCode.ERR_UnscopedRefAttributeInterfaceImplementation, "ref _f2").WithLocation(26, 39),
// (38,34): error CS9102: UnscopedRefAttribute cannot be applied to an interface implementation.
// [UnscopedRef] ref int I<int>.F1() => ref _f4; // 9
Diagnostic(ErrorCode.ERR_UnscopedRefAttributeInterfaceImplementation, "F1").WithLocation(38, 34),
// (39,31): error CS9102: UnscopedRefAttribute cannot be applied to an interface implementation.
// [UnscopedRef] void I<int>.F2() { } // 10
Diagnostic(ErrorCode.ERR_UnscopedRefAttributeInterfaceImplementation, "F2").WithLocation(39, 31),
// (40,31): error CS9102: UnscopedRefAttribute cannot be applied to an interface implementation.
// [UnscopedRef] void I<int>.F3(out R<int> r) { r = new R<int>(ref _f4); } // 11
Diagnostic(ErrorCode.ERR_UnscopedRefAttributeInterfaceImplementation, "F3").WithLocation(40, 31),
// (41,39): error CS9102: UnscopedRefAttribute cannot be applied to an interface implementation.
// [UnscopedRef] ref int I<int>.P => ref _f4; // 12
Diagnostic(ErrorCode.ERR_UnscopedRefAttributeInterfaceImplementation, "ref _f4").WithLocation(41, 39));
}
[Fact]
[WorkItem(64508, "https://github.com/dotnet/roslyn/issues/64508")]
public void UnscopedRefAttribute_InterfaceImplementation_03()
{
string source = """
using System.Diagnostics.CodeAnalysis;
interface I1<T>
{
ref T P1 { get; }
}
interface I2<T>
{
T P2 { get; set; }
}
interface I3<T>
{
T P3 { set; }
}
struct S1 : I1<int>, I2<int>
{
[UnscopedRef] public ref int P1 => throw null; // 1
[UnscopedRef] public int P2 { get; set; } // 2, 3
}
struct S2 : I1<int>, I2<int>
{
public ref int P1 { [UnscopedRef] get => throw null; } // 4
public int P2 { [UnscopedRef] get; set; } // 5
}
struct S3 : I2<int>, I3<int>
{
public int P2 { get; [UnscopedRef] set; } // 6
public int P3 { [UnscopedRef] set { } } // 7
}
""";
var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70);
comp.VerifyEmitDiagnostics(
// (16,40): error CS9102: UnscopedRefAttribute cannot be applied to an interface implementation.
// [UnscopedRef] public ref int P1 => throw null; // 1
Diagnostic(ErrorCode.ERR_UnscopedRefAttributeInterfaceImplementation, "throw null").WithLocation(16, 40),
// (17,35): error CS9102: UnscopedRefAttribute cannot be applied to an interface implementation.
// [UnscopedRef] public int P2 { get; set; } // 2, 3
Diagnostic(ErrorCode.ERR_UnscopedRefAttributeInterfaceImplementation, "get").WithLocation(17, 35),
// (17,40): error CS9102: UnscopedRefAttribute cannot be applied to an interface implementation.
// [UnscopedRef] public int P2 { get; set; } // 2, 3
Diagnostic(ErrorCode.ERR_UnscopedRefAttributeInterfaceImplementation, "set").WithLocation(17, 40),
// (21,39): error CS9102: UnscopedRefAttribute cannot be applied to an interface implementation.
// public ref int P1 { [UnscopedRef] get => throw null; } // 4
Diagnostic(ErrorCode.ERR_UnscopedRefAttributeInterfaceImplementation, "get").WithLocation(21, 39),
// (22,35): error CS9102: UnscopedRefAttribute cannot be applied to an interface implementation.
// public int P2 { [UnscopedRef] get; set; } // 5
Diagnostic(ErrorCode.ERR_UnscopedRefAttributeInterfaceImplementation, "get").WithLocation(22, 35),
// (26,40): error CS9102: UnscopedRefAttribute cannot be applied to an interface implementation.
// public int P2 { get; [UnscopedRef] set; } // 6
Diagnostic(ErrorCode.ERR_UnscopedRefAttributeInterfaceImplementation, "set").WithLocation(26, 40),
// (27,35): error CS9102: UnscopedRefAttribute cannot be applied to an interface implementation.
// public int P3 { [UnscopedRef] set { } } // 7
Diagnostic(ErrorCode.ERR_UnscopedRefAttributeInterfaceImplementation, "set").WithLocation(27, 35));
}
[Fact]
public void UnscopedRefAttribute_InterfaceImplementation_04()
{
string source = """
using System.Diagnostics.CodeAnalysis;
interface I<T>
{
ref T F();
ref T P { get; }
}
struct S : I<int>
{
private int _f;
[UnscopedRef] public ref int F() => ref _f;
[UnscopedRef] public ref int P => ref _f;
ref int I<int>.F() => throw null;
ref int I<int>.P => throw null;
}
""";
var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70);
comp.VerifyEmitDiagnostics();
}
[Fact]
public void UnscopedRefAttribute_InterfaceImplementation_05()
{
string source = """
using System.Diagnostics.CodeAnalysis;
interface I<T>
{
ref T F1();
[UnscopedRef] ref T F2(); // 1
}
class C1 : I<int>
{
private int _f1;
[UnscopedRef] public ref int F1() => ref _f1; // 2
[UnscopedRef] public ref int F2() => ref _f1; // 3
}
class C2 : I<int>
{
private int _f2;
[UnscopedRef] ref int I<int>.F1() => ref _f2; // 4
[UnscopedRef] ref int I<int>.F2() => ref _f2; // 5
}
""";
var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70);
comp.VerifyEmitDiagnostics(
// (5,6): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members.
// [UnscopedRef] ref T F2(); // 1
Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(5, 6),
// (10,6): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members.
// [UnscopedRef] public ref int F1() => ref _f1; // 2
Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(10, 6),
// (11,6): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members.
// [UnscopedRef] public ref int F2() => ref _f1; // 3
Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(11, 6),
// (16,6): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members.
// [UnscopedRef] ref int I<int>.F1() => ref _f2; // 4
Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(16, 6),
// (17,6): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members.
// [UnscopedRef] ref int I<int>.F2() => ref _f2; // 5
Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(17, 6));
}
[Fact]
public void UnscopedRefAttribute_InterfaceImplementation_06()
{
string source = """
using System.Diagnostics.CodeAnalysis;
interface I<T>
{
ref T F();
ref T P { get; }
}
class A
{
[UnscopedRef] public ref int F() => throw null; // 1
[UnscopedRef] public ref int P => throw null; // 2
}
class B : A, I<int>
{
}
""";
var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70);
comp.VerifyEmitDiagnostics(
// (9,6): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members.
// [UnscopedRef] public ref int F() => throw null; // 1
Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(9, 6),
// (10,6): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members.
// [UnscopedRef] public ref int P => throw null; // 2
Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(10, 6));
}
[ConditionalFact(typeof(CoreClrOnly))]
public void UnscopedRefAttribute_InterfaceImplementation_07()
{
string source = """
using System.Diagnostics.CodeAnalysis;
interface IA<T>
{
ref T F();
ref T P { get; }
}
interface IB : IA<int>
{
[UnscopedRef] ref int IA<int>.F() => throw null; // 1
[UnscopedRef] ref int IA<int>.P => throw null; // 2
}
""";
var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70);
comp.VerifyEmitDiagnostics(
// (9,6): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members.
// [UnscopedRef] ref int IA<int>.F() => throw null; // 1
Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(9, 6),
// (10,6): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members.
// [UnscopedRef] ref int IA<int>.P => throw null; // 2
Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(10, 6));
}
[Fact]
public void UnscopedRefAttribute_InterfaceImplementation_08()
{
string source = """
#pragma warning disable 67
using System.Diagnostics.CodeAnalysis;
delegate void D<T>();
interface I<T>
{
event D<T> E;
}
class C1 : I<int>
{
[UnscopedRef] public event D<int> E; // 1
}
class C2 : I<int>
{
[UnscopedRef] public event D<int> E { add { } remove { } } // 2
}
class C3 : I<object>
{
[UnscopedRef] event D<object> I<object>.E { add { } remove { } } // 3
}
struct S1 : I<int>
{
[UnscopedRef] public event D<int> E; // 4
}
struct S2 : I<int>
{
[UnscopedRef] public event D<int> E { add { } remove { } } // 5
}
struct S3 : I<object>
{
[UnscopedRef] event D<object> I<object>.E { add { } remove { } } // 6
}
""";
var comp = CreateCompilation(new[] { source, UnscopedRefAttributeDefinition });
comp.VerifyEmitDiagnostics(
// (10,6): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members.
// [UnscopedRef] public event D<int> E; // 1
Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(10, 6),
// (14,6): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members.
// [UnscopedRef] public event D<int> E { add { } remove { } } // 2
Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(14, 6),
// (18,6): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members.
// [UnscopedRef] event D<object> I<object>.E { add { } remove { } } // 3
Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(18, 6),
// (22,6): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members.
// [UnscopedRef] public event D<int> E; // 4
Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(22, 6),
// (26,6): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members.
// [UnscopedRef] public event D<int> E { add { } remove { } } // 5
Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(26, 6),
// (30,6): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members.
// [UnscopedRef] event D<object> I<object>.E { add { } remove { } } // 6
Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(30, 6));
}
[Fact]
public void UnscopedRefAttribute_InterfaceImplementation_09()
{
string source = """
#pragma warning disable 67
using System.Diagnostics.CodeAnalysis;
delegate void D<T>();
interface I<T>
{
event D<T> E1;
event D<T> E2;
}
class C1 : I<int>
{
public event D<int> E1 { [UnscopedRef] add { } remove { } } // 1
public event D<int> E2 { add { } [UnscopedRef] remove { } } // 2
}
class C2 : I<object>
{
event D<object> I<object>.E1 { [UnscopedRef] add { } remove { } } // 3
event D<object> I<object>.E2 { add { } [UnscopedRef] remove { } } // 4
}
struct S1 : I<int>
{
public event D<int> E1 { [UnscopedRef] add { } remove { } } // 5
public event D<int> E2 { add { } [UnscopedRef] remove { } } // 6
}
struct S2 : I<object>
{
event D<object> I<object>.E1 { [UnscopedRef] add { } remove { } } // 7
event D<object> I<object>.E2 { add { } [UnscopedRef] remove { } } // 8
}
""";
var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70);
comp.VerifyEmitDiagnostics(
// (11,31): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members.
// public event D<int> E1 { [UnscopedRef] add { } remove { } } // 1
Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(11, 31),
// (12,39): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members.
// public event D<int> E2 { add { } [UnscopedRef] remove { } } // 2
Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(12, 39),
// (16,37): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members.
// event D<object> I<object>.E1 { [UnscopedRef] add { } remove { } } // 3
Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(16, 37),
// (17,45): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members.
// event D<object> I<object>.E2 { add { } [UnscopedRef] remove { } } // 4
Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(17, 45),
// (21,31): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members.
// public event D<int> E1 { [UnscopedRef] add { } remove { } } // 5
Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(21, 31),
// (22,39): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members.
// public event D<int> E2 { add { } [UnscopedRef] remove { } } // 6
Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(22, 39),
// (26,37): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members.
// event D<object> I<object>.E1 { [UnscopedRef] add { } remove { } } // 7
Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(26, 37),
// (27,45): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members.
// event D<object> I<object>.E2 { add { } [UnscopedRef] remove { } } // 8
Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(27, 45));
}
[ConditionalFact(typeof(CoreClrOnly))]
public void UnscopedRefAttribute_InterfaceImplementation_10()
{
string source = """
using System.Diagnostics.CodeAnalysis;
delegate void D<T>();
interface I<T>
{
event D<T> E;
}
interface IA : I<int>
{
[UnscopedRef] event D<int> I<int>.E { add { } remove { } } // 1
}
interface IB : I<object>
{
event D<object> I<object>.E { [UnscopedRef] add { } remove { } } // 2
}
interface IC : I<string>
{
event D<string> I<string>.E { add { } [UnscopedRef] remove { } } // 3
}
""";
var comp = CreateCompilation(new[] { source, UnscopedRefAttributeDefinition }, targetFramework: TargetFramework.Net60);
comp.VerifyEmitDiagnostics(
// (9,6): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members.
// [UnscopedRef] event D<int> I<int>.E { add { } remove { } } // 1
Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(9, 6),
// (13,36): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members.
// event D<object> I<object>.E { [UnscopedRef] add { } remove { } } // 2
Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(13, 36),
// (17,44): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members.
// event D<string> I<string>.E { add { } [UnscopedRef] remove { } } // 3
Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(17, 44));
}
[Fact]
public void UnscopedRefAttribute_InterfaceImplementation_11()
{
string source = """
#pragma warning disable 67
using System.Diagnostics.CodeAnalysis;
delegate void D<T>();
interface I<T>
{
[UnscopedRef] event D<T> E; // 1
}
class C : I<int>
{
[UnscopedRef] public event D<int> E; // 2
}
struct S : I<object>
{
[UnscopedRef] event D<object> I<object>.E { add { } remove { } } // 3
}
""";
var comp = CreateCompilation(new[] { source, UnscopedRefAttributeDefinition });
comp.VerifyEmitDiagnostics(
// (6,6): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members.
// [UnscopedRef] event D<T> E; // 1
Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(6, 6),
// (10,6): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members.
// [UnscopedRef] public event D<int> E; // 2
Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(10, 6),
// (14,6): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members.
// [UnscopedRef] event D<object> I<object>.E { add { } remove { } } // 3
Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(14, 6));
}
[Theory]
[InlineData("class")]
[InlineData("struct")]
public void UnscopedRefAttribute_InterfaceImplementation_12(string type)
{
string source = $$"""
using System.Diagnostics.CodeAnalysis;
delegate void D<T>();
ref struct R<T> { }
interface I<T>
{
static abstract R<T> F();
static abstract R<T> P1 { get; }
static abstract R<T> P2 { get; set; }
static abstract event D<T> E;
}
{{type}} C1 : I<int>
{
[UnscopedRef] public static R<int> F() => default; // 1
[UnscopedRef] public static R<int> P1 { get { return default; } set { } } // 2
public static R<int> P2 { [UnscopedRef] get { return default; } [UnscopedRef] set { } } // 3, 4
public static event D<int> E { [UnscopedRef] add { } [UnscopedRef] remove { } } // 5, 6
}
{{type}} C2 : I<object>
{
[UnscopedRef] static R<object> I<object>.F() => default; // 7
[UnscopedRef] static R<object> I<object>.P1 => default; // 8
static R<object> I<object>.P2 { [UnscopedRef] get { return default; } [UnscopedRef] set { } } // 9, 10
static event D<object> I<object>.E { [UnscopedRef] add { } [UnscopedRef] remove { } } // 11, 12
}
""";
var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70);
comp.VerifyEmitDiagnostics(
// (13,6): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members.
// [UnscopedRef] public static R<int> F() => default; // 1
Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(13, 6),
// (14,6): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members.
// [UnscopedRef] public static R<int> P1 { get { return default; } set { } } // 2
Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(14, 6),
// (15,32): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members.
// public static R<int> P2 { [UnscopedRef] get { return default; } [UnscopedRef] set { } } // 3, 4
Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(15, 32),
// (15,70): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members.
// public static R<int> P2 { [UnscopedRef] get { return default; } [UnscopedRef] set { } } // 3, 4
Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(15, 70),
// (16,37): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members.
// public static event D<int> E { [UnscopedRef] add { } [UnscopedRef] remove { } } // 5, 6
Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(16, 37),
// (16,59): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members.
// public static event D<int> E { [UnscopedRef] add { } [UnscopedRef] remove { } } // 5, 6
Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(16, 59),
// (20,6): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members.
// [UnscopedRef] static R<object> I<object>.F() => default; // 7
Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(20, 6),
// (21,6): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members.
// [UnscopedRef] static R<object> I<object>.P1 => default; // 8
Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(21, 6),
// (22,38): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members.
// static R<object> I<object>.P2 { [UnscopedRef] get { return default; } [UnscopedRef] set { } } // 9, 10
Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(22, 38),
// (22,76): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members.
// static R<object> I<object>.P2 { [UnscopedRef] get { return default; } [UnscopedRef] set { } } // 9, 10
Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(22, 76),
// (23,43): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members.
// static event D<object> I<object>.E { [UnscopedRef] add { } [UnscopedRef] remove { } } // 11, 12
Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(23, 43),
// (23,65): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members.
// static event D<object> I<object>.E { [UnscopedRef] add { } [UnscopedRef] remove { } } // 11, 12
Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(23, 65));
}
[Fact]
public void UnscopedRefAttribute_InterfaceImplementation_13()
{
string source = """
using System.Diagnostics.CodeAnalysis;
delegate void D<T>();
ref struct R<T> { }
interface IA<T>
{
static abstract R<T> F();
static abstract R<T> P1 { get; }
static abstract R<T> P2 { get; set; }
static abstract event D<T> E;
}
interface IB : IA<object>
{
[UnscopedRef] static R<object> IA<object>.F() => default; // 1
[UnscopedRef] static R<object> IA<object>.P1 => default; // 2
static R<object> IA<object>.P2 { [UnscopedRef] get { return default; } [UnscopedRef] set { } } // 3, 4
static event D<object> IA<object>.E { [UnscopedRef] add { } [UnscopedRef] remove { } } // 5, 6
}
""";
var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70);
comp.VerifyEmitDiagnostics(
// (13,6): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members.
// [UnscopedRef] static R<object> IA<object>.F() => default; // 1
Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(13, 6),
// (14,6): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members.
// [UnscopedRef] static R<object> IA<object>.P1 => default; // 2
Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(14, 6),
// (15,39): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members.
// static R<object> IA<object>.P2 { [UnscopedRef] get { return default; } [UnscopedRef] set { } } // 3, 4
Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(15, 39),
// (15,77): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members.
// static R<object> IA<object>.P2 { [UnscopedRef] get { return default; } [UnscopedRef] set { } } // 3, 4
Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(15, 77),
// (16,44): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members.
// static event D<object> IA<object>.E { [UnscopedRef] add { } [UnscopedRef] remove { } } // 5, 6
Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(16, 44),
// (16,66): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members.
// static event D<object> IA<object>.E { [UnscopedRef] add { } [UnscopedRef] remove { } } // 5, 6
Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(16, 66));
}
[Fact]
public void UnscopedRefAttribute_Overrides_07()
{
string source = """
using System.Diagnostics.CodeAnalysis;
abstract class A<T>
{
public abstract ref T F1();
[UnscopedRef] public abstract ref T F2(); // 1
}
class B1 : A<int>
{
private int _f1;
public override ref int F1() => ref _f1;
public override ref int F2() => ref _f1;
}
class B2 : A<string>
{
private string _f2;
[UnscopedRef] public override ref string F1() => ref _f2; // 2
[UnscopedRef] public override ref string F2() => ref _f2; // 3
}
""";
var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70);
comp.VerifyEmitDiagnostics(
// (5,6): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members.
// [UnscopedRef] public abstract ref T F2(); // 1
Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(5, 6),
// (16,6): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members.
// [UnscopedRef] public override ref string F1() => ref _f2; // 2
Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(16, 6),
// (17,6): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members.
// [UnscopedRef] public override ref string F2() => ref _f2; // 3
Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(17, 6));
}
[WorkItem(64507, "https://github.com/dotnet/roslyn/issues/64507")]
[Theory]
[InlineData(0)]
[InlineData(-1)]
[InlineData(10)]
[InlineData(11)]
[InlineData(12)]
[InlineData(int.MinValue)]
[InlineData(int.MaxValue)]
public void RefSafetyRulesAttribute_Version(int version)
{
var sourceA =
$@".assembly extern mscorlib {{ .ver 4:0:0:0 .publickeytoken = (B7 7A 5C 56 19 34 E0 89) }}
.assembly '<<GeneratedFileName>>' {{ }}
.module '<<GeneratedFileName>>.dll'
.custom instance void System.Runtime.CompilerServices.RefSafetyRulesAttribute::.ctor(int32) = {{ int32({version}) }}
.class private System.Runtime.CompilerServices.RefSafetyRulesAttribute extends [mscorlib]System.Attribute
{{
.method public hidebysig specialname rtspecialname instance void .ctor(int32 version) cil managed {{ ret }}
.field public int32 Version
}}
.class public A
{{
.method public static int32& F1([out] int32& i)
{{
ldnull
throw
}}
}}
";
var refA = CompileIL(sourceA, prependDefaultHeader: false);
var sourceB =
@"class B
{
static ref int F2(out int i) => ref A.F1(out i);
}";
var comp = CreateCompilation(sourceB, references: new[] { refA });
if (version == 11)
{
comp.VerifyDiagnostics();
}
else
{
comp.VerifyDiagnostics(
// (3,41): error CS9103: 'A.F1(out int)' is defined in a module with an unrecognized RefSafetyRulesAttribute version, expecting '11'.
// static ref int F2(out int i) => ref A.F1(out i);
Diagnostic(ErrorCode.ERR_UnrecognizedRefSafetyRulesAttributeVersion, "A.F1").WithArguments("A.F1(out int)").WithLocation(3, 41));
}
var method = comp.GetMember<MethodSymbol>("A.F1");
VerifyParameterSymbol(method.Parameters[0], "out System.Int32 i", RefKind.Out, version == 11 ? ScopedKind.ScopedRef : ScopedKind.None);
Assert.Equal(version == 11, method.ContainingModule.UseUpdatedEscapeRules);
}
[WorkItem(64507, "https://github.com/dotnet/roslyn/issues/64507")]
[Fact]
public void RefSafetyRulesAttribute_UnrecognizedConstructor_NoArguments()
{
// [module: RefSafetyRules()]
var sourceA = """
.assembly extern mscorlib { .ver 4:0:0:0 .publickeytoken = (B7 7A 5C 56 19 34 E0 89) }
.assembly '<<GeneratedFileName>>' { }
.module '<<GeneratedFileName>>.dll'
.custom instance void System.Runtime.CompilerServices.RefSafetyRulesAttribute::.ctor() = ( 01 00 00 00 )
.class private System.Runtime.CompilerServices.RefSafetyRulesAttribute extends [mscorlib]System.Attribute
{
.method public hidebysig specialname rtspecialname instance void .ctor() cil managed { ret }
}
.class public A
{
.method public static int32& F1([out] int32& i) { ldnull throw }
}
""";
var refA = CompileIL(sourceA, prependDefaultHeader: false);
var sourceB = """
class B
{
static ref int F2(out int i) => ref A.F1(out i);
}
""";
var comp = CreateCompilation(sourceB, references: new[] { refA });
comp.VerifyDiagnostics(
// (3,41): error CS9103: 'A.F1(out int)' is defined in a module with an unrecognized RefSafetyRulesAttribute version, expecting '11'.
// static ref int F2(out int i) => ref A.F1(out i);
Diagnostic(ErrorCode.ERR_UnrecognizedRefSafetyRulesAttributeVersion, "A.F1").WithArguments("A.F1(out int)").WithLocation(3, 41));
var method = comp.GetMember<MethodSymbol>("A.F1");
VerifyParameterSymbol(method.Parameters[0], "out System.Int32 i", RefKind.Out, ScopedKind.None);
Assert.False(method.ContainingModule.UseUpdatedEscapeRules);
}
[WorkItem(64507, "https://github.com/dotnet/roslyn/issues/64507")]
[Fact]
public void RefSafetyRulesAttribute_UnrecognizedConstructor_StringArgument()
{
// [module: RefSafetyRules("11")]
var sourceA = """
.assembly extern mscorlib { .ver 4:0:0:0 .publickeytoken = (B7 7A 5C 56 19 34 E0 89) }
.assembly '<<GeneratedFileName>>' { }
.module '<<GeneratedFileName>>.dll'
.custom instance void System.Runtime.CompilerServices.RefSafetyRulesAttribute::.ctor(string) = {string('11')}
.class private System.Runtime.CompilerServices.RefSafetyRulesAttribute extends [mscorlib]System.Attribute
{
.method public hidebysig specialname rtspecialname instance void .ctor(string version) cil managed { ret }
}
.class public A
{
.method public static int32& F1([out] int32& i) { ldnull throw }
}
""";
var refA = CompileIL(sourceA, prependDefaultHeader: false);
var sourceB = """
class B
{
static ref int F2(out int i) => ref A.F1(out i);
}
""";
var comp = CreateCompilation(sourceB, references: new[] { refA });
comp.VerifyDiagnostics(
// (3,41): error CS9103: 'A.F1(out int)' is defined in a module with an unrecognized RefSafetyRulesAttribute version, expecting '11'.
// static ref int F2(out int i) => ref A.F1(out i);
Diagnostic(ErrorCode.ERR_UnrecognizedRefSafetyRulesAttributeVersion, "A.F1").WithArguments("A.F1(out int)").WithLocation(3, 41));
var method = comp.GetMember<MethodSymbol>("A.F1");
VerifyParameterSymbol(method.Parameters[0], "out System.Int32 i", RefKind.Out, ScopedKind.None);
Assert.False(method.ContainingModule.UseUpdatedEscapeRules);
}
/// <summary>
/// Use updated escape rules with either -langversion:11 or higher, or
/// with System.Runtime.CompilerServices.RuntimeFeature.ByRefFields.
/// </summary>
[Theory]
[InlineData(LanguageVersion.CSharp10, TargetFramework.Net60, false, false)]
[InlineData(LanguageVersion.CSharp11, TargetFramework.Net60, false, true)]
[InlineData(LanguageVersion.Latest, TargetFramework.Net60, false, true)]
[InlineData(LanguageVersion.CSharp10, TargetFramework.Net70, true, true)]
[InlineData(LanguageVersion.CSharp11, TargetFramework.Net70, true, true)]
[InlineData(LanguageVersion.Latest, TargetFramework.Net70, true, true)]
public void UseUpdatedEscapeRules(LanguageVersion languageVersion, TargetFramework targetFramework, bool supportsRefFields, bool expectedUseUpdatedEscapeRules)
{
var source =
@"class Program
{
static ref T F1<T>(out T t) => throw null;
static ref T F2<T>() => ref F1(out T t);
}";
var comp = CreateCompilation(source, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion), targetFramework: targetFramework);
if (expectedUseUpdatedEscapeRules)
{
comp.VerifyEmitDiagnostics();
}
else
{
comp.VerifyEmitDiagnostics(
// (4,33): error CS8347: Cannot use a result of 'Program.F1<T>(out T)' in this context because it may expose variables referenced by parameter 't' outside of their declaration scope
// static ref T F2<T>() => ref F1(out T t);
Diagnostic(ErrorCode.ERR_EscapeCall, "F1(out T t)").WithArguments("Program.F1<T>(out T)", "t").WithLocation(4, 33),
// (4,40): error CS8168: Cannot return local 't' by reference because it is not a ref local
// static ref T F2<T>() => ref F1(out T t);
Diagnostic(ErrorCode.ERR_RefReturnLocal, "T t").WithArguments("t").WithLocation(4, 40));
}
Assert.Equal(supportsRefFields, comp.SourceAssembly.RuntimeSupportsByRefFields);
var runtimeFeature = (FieldSymbol)comp.GetMember<NamedTypeSymbol>("System.Runtime.CompilerServices.RuntimeFeature").GetMembers("ByRefFields").SingleOrDefault();
Assert.Equal(supportsRefFields, runtimeFeature is { });
if (supportsRefFields)
{
Assert.Equal("System.String System.Runtime.CompilerServices.RuntimeFeature.ByRefFields", runtimeFeature.ToTestDisplayString());
}
var method = comp.GetMember<MethodSymbol>("Program.F1");
VerifyParameterSymbol(method.Parameters[0], "out T t", RefKind.Out, expectedUseUpdatedEscapeRules ? ScopedKind.ScopedRef : ScopedKind.None);
Assert.Equal(expectedUseUpdatedEscapeRules, method.UseUpdatedEscapeRules);
Assert.Equal(expectedUseUpdatedEscapeRules, method.ContainingModule.UseUpdatedEscapeRules);
}
[WorkItem(63691, "https://github.com/dotnet/roslyn/issues/63691")]
[Theory]
[CombinatorialData]
public void DetectUpdatedEscapeRulesFromCorlib(
[CombinatorialValues(LanguageVersion.CSharp10, LanguageVersion.CSharp11)] LanguageVersion languageVersion,
[CombinatorialValues(6, 7, 8)] int majorVersion)
{
var source0 =
@"namespace System
{
public class Object { }
public class String { }
public abstract class ValueType { }
public struct Void { }
public struct Boolean { }
public struct Int32 { }
public class Attribute { }
public class AttributeUsageAttribute : Attribute
{
public AttributeUsageAttribute(AttributeTargets t) { }
public bool AllowMultiple { get; set; }
public bool Inherited { get; set; }
}
public struct Enum { }
public enum AttributeTargets { }
}";
var assemblyIdentity = new AssemblyIdentity("System.Runtime", new System.Version(majorVersion, 0, 0, 0));
var comp = CreateCompilation(assemblyIdentity, new[] { source0 }, references: null, parseOptions: TestOptions.Regular10);
var ref0 = comp.EmitToImageReference(Microsoft.CodeAnalysis.Emit.EmitOptions.Default.WithRuntimeMetadataVersion("0.0.0.0"));
var source1 =
@"public class A<T>
{
public static void F() { }
}";
comp = CreateEmptyCompilation(source1, references: new[] { ref0 }, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion));
comp.VerifyEmitDiagnostics();
var ref1 = comp.EmitToImageReference();
var source2 =
@"class B : A<int>
{
static void Main() { }
}";
comp = CreateEmptyCompilation(source2, references: new[] { ref0, ref1 }, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion));
comp.VerifyEmitDiagnostics();
var module = comp.GetMember<NamedTypeSymbol>("A").ContainingModule;
Assert.Equal(assemblyIdentity, module.ReferencedAssemblies.Single());
Assert.Equal(assemblyIdentity, module.ContainingAssembly.CorLibrary.Identity);
Assert.Equal(languageVersion == LanguageVersion.CSharp11, module.UseUpdatedEscapeRules);
module = comp.GetMember<NamedTypeSymbol>("System.Object").ContainingModule;
Assert.False(module.UseUpdatedEscapeRules);
}
[WorkItem(63691, "https://github.com/dotnet/roslyn/issues/63691")]
[Theory]
[CombinatorialData]
public void DetectUpdatedEscapeRulesFromCorlib_Retargeting(
[CombinatorialValues(LanguageVersion.CSharp10, LanguageVersion.CSharp11)] LanguageVersion languageVersion,
[CombinatorialValues(7, 8)] int higherVersion)
{
var source0 =
@"namespace System
{
public class Object { }
public class String { }
public abstract class ValueType { }
public struct Void { }
public struct Boolean { }
public struct Int32 { }
public class Attribute { }
public class AttributeUsageAttribute : Attribute
{
public AttributeUsageAttribute(AttributeTargets t) { }
public bool AllowMultiple { get; set; }
public bool Inherited { get; set; }
}
public struct Enum { }
public enum AttributeTargets { }
}";
var assemblyIdentityLowerVersion = new AssemblyIdentity("System.Runtime", new System.Version(6, 0, 0, 0));
var comp = CreateCompilation(assemblyIdentityLowerVersion, new[] { source0 }, references: null, parseOptions: TestOptions.Regular10);
var refLowerVersion = comp.EmitToImageReference();
var assemblyIdentityHigherVersion = new AssemblyIdentity("System.Runtime", new System.Version(higherVersion, 0, 0, 0));
comp = CreateCompilation(assemblyIdentityHigherVersion, new[] { source0 }, references: null, parseOptions: TestOptions.Regular10);
var refHigherVersion = comp.EmitToImageReference();
var source1 =
@"public class A<T>
{
public static void F() { }
}";
comp = CreateEmptyCompilation(source1, references: new[] { refLowerVersion }, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion));
comp.VerifyEmitDiagnostics();
var ref1 = comp.EmitToImageReference();
var module = comp.GetMember<NamedTypeSymbol>("System.Object").ContainingModule;
Assert.False(module.UseUpdatedEscapeRules);
module = comp.GetMember<NamedTypeSymbol>("A").ContainingModule;
Assert.Equal(languageVersion == LanguageVersion.CSharp11, module.UseUpdatedEscapeRules);
Assert.Equal(languageVersion == LanguageVersion.CSharp11, ((SourceModuleSymbol)module).RequiresRefSafetyRulesAttribute());
var source2 =
@"class B : A<int>
{
static void Main() { }
}";
comp = CreateEmptyCompilation(source2, references: new[] { refHigherVersion, ref1 }, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion));
comp.VerifyEmitDiagnostics();
module = comp.GetMember<NamedTypeSymbol>("A").ContainingModule;
Assert.Equal(assemblyIdentityLowerVersion, module.ReferencedAssemblies.Single());
Assert.Equal(assemblyIdentityHigherVersion, module.ContainingAssembly.CorLibrary.Identity);
Assert.Equal(languageVersion == LanguageVersion.CSharp11, module.UseUpdatedEscapeRules);
module = module.ContainingAssembly.CorLibrary.Modules[0];
Assert.False(module.UseUpdatedEscapeRules);
}
[WorkItem(63691, "https://github.com/dotnet/roslyn/issues/63691")]
[Theory]
[InlineData("System.Runtime", 7, 0, false)]
[InlineData("System.Runtime", 7, 1, false)]
[InlineData("System.Runtime", 8, 0, false)]
[InlineData("mscorlib", 7, 0, false)]
[InlineData("System.Core", 7, 0, false)]
public void DetectUpdatedEscapeRulesFromCorlib_SystemRuntime70Only(string assemblyName, int majorVersion, int minorVersion, bool expectedUseUpdatedEscapeRules)
{
var source0 =
@"namespace System
{
public class Object { }
public class String { }
public abstract class ValueType { }
public struct Void { }
public struct Boolean { }
public struct Int32 { }
public class Attribute { }
public class AttributeUsageAttribute : Attribute
{
public AttributeUsageAttribute(AttributeTargets t) { }
public bool AllowMultiple { get; set; }
public bool Inherited { get; set; }
}
public struct Enum { }
public enum AttributeTargets { }
}";
var assemblyIdentity = new AssemblyIdentity(assemblyName, new System.Version(majorVersion, minorVersion, 0, 0));
var comp = CreateCompilation(assemblyIdentity, new[] { source0 }, references: null, parseOptions: TestOptions.Regular10);
var ref0 = comp.EmitToImageReference(Microsoft.CodeAnalysis.Emit.EmitOptions.Default.WithRuntimeMetadataVersion("0.0.0.0"));
var source1 =
@"public class A<T>
{
public static void F() { }
}";
comp = CreateEmptyCompilation(source1, references: new[] { ref0 }, parseOptions: TestOptions.Regular10);
comp.VerifyEmitDiagnostics();
var ref1 = comp.EmitToImageReference();
var module = comp.GetMember<NamedTypeSymbol>("System.Object").ContainingModule;
Assert.Equal(expectedUseUpdatedEscapeRules, module.UseUpdatedEscapeRules);
module = comp.GetMember<NamedTypeSymbol>("A").ContainingModule;
Assert.False(module.UseUpdatedEscapeRules);
Assert.False(((SourceModuleSymbol)module).RequiresRefSafetyRulesAttribute());
var source2 =
@"class B : A<int>
{
static void Main() { }
}";
comp = CreateEmptyCompilation(source2, references: new[] { ref0, ref1 });
comp.VerifyEmitDiagnostics();
module = comp.GetMember<NamedTypeSymbol>("A").ContainingModule;
Assert.Equal(assemblyIdentity, module.ReferencedAssemblies.Single());
Assert.Equal(assemblyIdentity, module.ContainingAssembly.CorLibrary.Identity);
Assert.Equal(expectedUseUpdatedEscapeRules, module.UseUpdatedEscapeRules);
module = comp.GetMember<NamedTypeSymbol>("System.Object").ContainingModule;
Assert.Equal(expectedUseUpdatedEscapeRules, module.UseUpdatedEscapeRules);
}
[Fact]
[WorkItem(63565, "https://github.com/dotnet/roslyn/issues/63565")]
public void UnscopedRefInInferredDelegateType_01()
{
var source =
@"
using System.Diagnostics.CodeAnalysis;
public ref struct RefStruct { }
public struct RegularStruct { }
delegate void D1(ref RefStruct s);
delegate void D2([UnscopedRef] out RegularStruct s);
delegate void D3([UnscopedRef] out RefStruct s);
public class C
{
public void M()
{
var a = (ref RefStruct s) => { };
var b = ([UnscopedRef] out RegularStruct s) => { };
var c = ([UnscopedRef] out RefStruct s) => { };
D1 x = (ref RefStruct s) => { };
D2 y = ([UnscopedRef] out RegularStruct s) => { };
D3 z = ([UnscopedRef] out RefStruct s) => { };
}
}
";
var comp = CreateCompilation(new[] { source, UnscopedRefAttributeDefinition }, options: TestOptions.ReleaseDll);
comp.VerifyEmitDiagnostics();
var tree = comp.SyntaxTrees[0];
var model = comp.GetSemanticModel(tree);
int count = 0;
foreach (var node in tree.GetRoot().DescendantNodes().OfType<VariableDeclaratorSyntax>().Where(d => d.Identifier.ValueText is "a" or "b" or "c"))
{
count++;
var type = (NamedTypeSymbol)model.GetDeclaredSymbol(node).GetSymbol<LocalSymbol>().Type;
Assert.True(type.IsImplicitlyDeclared);
Assert.True(type.IsAnonymousType);
Assert.Equal(ScopedKind.None, type.DelegateInvokeMethod.Parameters.Single().EffectiveScope);
}
Assert.Equal(3, count);
}
[Fact]
[WorkItem(63565, "https://github.com/dotnet/roslyn/issues/63565")]
public void UnscopedRefInInferredDelegateType_02()
{
var source =
@"
using System.Diagnostics.CodeAnalysis;
public ref struct RefStruct { }
public struct RegularStruct { }
delegate void D1(ref RefStruct s);
delegate void D2([UnscopedRef] out RegularStruct s);
delegate void D3([UnscopedRef] out RefStruct s);
public class C
{
public void M()
{
void localA(ref RefStruct s) { };
void localB([UnscopedRef] out RegularStruct s) { };
void localC([UnscopedRef] out RefStruct s) { };
var a = localA;
var b = localB;
var c = localC;
D1 x = localA;
D2 y = localB;
D3 z = localC;
}
}
";
var comp = CreateCompilation(new[] { source, UnscopedRefAttributeDefinition }, options: TestOptions.ReleaseDll);
comp.VerifyEmitDiagnostics();
var tree = comp.SyntaxTrees[0];
var model = comp.GetSemanticModel(tree);
int count = 0;
foreach (var node in tree.GetRoot().DescendantNodes().OfType<VariableDeclaratorSyntax>().Where(d => d.Identifier.ValueText is "a" or "b" or "c"))
{
count++;
var type = (NamedTypeSymbol)model.GetDeclaredSymbol(node).GetSymbol<LocalSymbol>().Type;
Assert.True(type.IsImplicitlyDeclared);
Assert.True(type.IsAnonymousType);
Assert.Equal(ScopedKind.None, type.DelegateInvokeMethod.Parameters.Single().EffectiveScope);
}
Assert.Equal(3, count);
}
[Fact]
[WorkItem(63565, "https://github.com/dotnet/roslyn/issues/63565")]
public void UnscopedRefInInferredDelegateType_03()
{
var source =
@"
using System.Diagnostics.CodeAnalysis;
public ref struct RefStruct { }
public struct RegularStruct { }
delegate void D1(ref RefStruct s);
delegate void D2([UnscopedRef] out RegularStruct s);
delegate void D3([UnscopedRef] out RefStruct s);
public class C1
{
public void M()
{
var a = A;
var b = B;
var c = C;
D1 x = A;
D2 y = B;
D3 z = C;
}
void A(ref RefStruct s) { }
void B([UnscopedRef] out RegularStruct s) { }
void C([UnscopedRef] out RefStruct s) { }
}
";
var comp = CreateCompilation(new[] { source, UnscopedRefAttributeDefinition }, options: TestOptions.ReleaseDll);
comp.VerifyEmitDiagnostics();
var tree = comp.SyntaxTrees[0];
var model = comp.GetSemanticModel(tree);
int count = 0;
foreach (var node in tree.GetRoot().DescendantNodes().OfType<VariableDeclaratorSyntax>().Where(d => d.Identifier.ValueText is "a" or "b" or "c"))
{
count++;
var type = (NamedTypeSymbol)model.GetDeclaredSymbol(node).GetSymbol<LocalSymbol>().Type;
Assert.True(type.IsImplicitlyDeclared);
Assert.True(type.IsAnonymousType);
Assert.Equal(ScopedKind.None, type.DelegateInvokeMethod.Parameters.Single().EffectiveScope);
}
Assert.Equal(3, count);
}
[Fact, WorkItem(63526, "https://github.com/dotnet/roslyn/issues/63526")]
public void UnscopedRef_ArgumentsMustMatch_01()
{
var source = """
using System.Diagnostics.CodeAnalysis;
ref struct RefByteContainer
{
public ref byte RB;
public RefByteContainer(ref byte rb)
{
RB = ref rb;
}
}
ref struct ByteContainer
{
public byte B;
[UnscopedRef]
public RefByteContainer ByteRef => new RefByteContainer(ref B);
[UnscopedRef]
public RefByteContainer GetByteRef() => new RefByteContainer(ref B);
}
public class Program
{
static void M11(ref ByteContainer bc)
{
// ok. because ref-safe-to-escape of 'this' in 'ByteContainer.ByteRef.get' is 'ReturnOnly',
// we know that 'ref bc' will not end up written to a ref field within 'bc'.
_ = bc.ByteRef;
}
static void M12(ref ByteContainer bc)
{
// ok. because ref-safe-to-escape of 'this' in 'ByteContainer.GetByteRef()' is 'ReturnOnly',
// we know that 'ref bc' will not end up written to a ref field within 'bc'.
_ = bc.GetByteRef();
}
static void M21(ref ByteContainer bc, ref RefByteContainer rbc)
{
// error. ref-safe-to-escape of 'bc' is 'ReturnOnly', therefore 'bc.ByteRef' can't be assigned to a ref parameter.
rbc = bc.ByteRef; // 1
}
static void M22(ref ByteContainer bc, ref RefByteContainer rbc)
{
// error. ref-safe-to-escape of 'bc' is 'ReturnOnly', therefore 'bc.ByteRef' can't be assigned to a ref parameter.
rbc = bc.GetByteRef(); // 2
}
static RefByteContainer M31(ref ByteContainer bc)
// ok. ref-safe-to-escape of 'bc' is 'ReturnOnly'.
=> bc.ByteRef;
static RefByteContainer M32(ref ByteContainer bc)
// ok. ref-safe-to-escape of 'bc' is 'ReturnOnly'.
=> bc.GetByteRef();
static RefByteContainer M41(scoped ref ByteContainer bc)
// error: `bc.ByteRef` may contain a reference to `bc`, whose ref-safe-to-escape is CurrentMethod.
=> bc.ByteRef; // 3
static RefByteContainer M42(scoped ref ByteContainer bc)
// error: `bc.GetByteRef()` may contain a reference to `bc`, whose ref-safe-to-escape is CurrentMethod.
=> bc.GetByteRef(); // 4
}
""";
var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70);
comp.VerifyDiagnostics(
// (42,15): error CS9077: Cannot return a parameter by reference 'bc' through a ref parameter; it can only be returned in a return statement
// rbc = bc.ByteRef; // 1
Diagnostic(ErrorCode.ERR_RefReturnOnlyParameter, "bc").WithArguments("bc").WithLocation(42, 15),
// (47,15): error CS9077: Cannot return a parameter by reference 'bc' through a ref parameter; it can only be returned in a return statement
// rbc = bc.GetByteRef(); // 2
Diagnostic(ErrorCode.ERR_RefReturnOnlyParameter, "bc").WithArguments("bc").WithLocation(47, 15),
// (60,12): error CS9075: Cannot return a parameter by reference 'bc' because it is scoped to the current method
// => bc.ByteRef; // 3
Diagnostic(ErrorCode.ERR_RefReturnScopedParameter, "bc").WithArguments("bc").WithLocation(60, 12),
// (64,12): error CS9075: Cannot return a parameter by reference 'bc' because it is scoped to the current method
// => bc.GetByteRef(); // 4
Diagnostic(ErrorCode.ERR_RefReturnScopedParameter, "bc").WithArguments("bc").WithLocation(64, 12));
}
[Fact]
public void LocalScope_01_UsingDecl()
{
var source =
@"#pragma warning disable 219
class Program
{
static void F(ref R r)
{
using scoped R r1 = default;
using scoped ref R r2 = ref r;
using scoped ref readonly R r5 = ref r;
}
}
ref struct R
{
public void Dispose() {}
}
";
var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10);
comp.VerifyEmitDiagnostics(
// (7,15): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater.
// using scoped R r1 = default;
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "scoped").WithArguments("ref fields", "11.0").WithLocation(7, 15),
// (8,15): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater.
// using scoped ref R r2 = ref r;
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "scoped").WithArguments("ref fields", "11.0").WithLocation(8, 15),
// (8,22): error CS1073: Unexpected token 'ref'
// using scoped ref R r2 = ref r;
Diagnostic(ErrorCode.ERR_UnexpectedToken, "ref").WithArguments("ref").WithLocation(8, 22),
// (9,15): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater.
// using scoped ref readonly R r5 = ref r;
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "scoped").WithArguments("ref fields", "11.0").WithLocation(9, 15),
// (9,22): error CS1073: Unexpected token 'ref'
// using scoped ref readonly R r5 = ref r;
Diagnostic(ErrorCode.ERR_UnexpectedToken, "ref").WithArguments("ref").WithLocation(9, 22)
);
verify(comp);
comp = CreateCompilation(source);
comp.VerifyEmitDiagnostics(
// (8,22): error CS1073: Unexpected token 'ref'
// using scoped ref R r2 = ref r;
Diagnostic(ErrorCode.ERR_UnexpectedToken, "ref").WithArguments("ref").WithLocation(8, 22),
// (9,22): error CS1073: Unexpected token 'ref'
// using scoped ref readonly R r5 = ref r;
Diagnostic(ErrorCode.ERR_UnexpectedToken, "ref").WithArguments("ref").WithLocation(9, 22)
);
verify(comp);
static void verify(CSharpCompilation comp)
{
var tree = comp.SyntaxTrees[0];
var model = comp.GetSemanticModel(tree);
var decls = tree.GetRoot().DescendantNodes().OfType<VariableDeclaratorSyntax>().ToArray();
var locals = decls.Select(d => model.GetDeclaredSymbol(d).GetSymbol<LocalSymbol>()).ToArray();
VerifyLocalSymbol(locals[0], "scoped R r1", RefKind.None, ScopedKind.ScopedValue);
VerifyLocalSymbol(locals[1], "scoped ref R r2", RefKind.Ref, ScopedKind.ScopedRef);
VerifyLocalSymbol(locals[2], "scoped ref readonly R r5", RefKind.RefReadOnly, ScopedKind.ScopedRef);
foreach (var decl in decls)
{
var type = ((VariableDeclarationSyntax)decl.Parent).Type;
Assert.True(SyntaxFacts.IsInTypeOnlyContext(type));
Assert.True(SyntaxFacts.IsInTypeOnlyContext(type.SkipScoped(out _)));
Assert.True(SyntaxFacts.IsInTypeOnlyContext(type.SkipScoped(out _).SkipRef()));
Assert.Null(model.GetSymbolInfo(type).Symbol);
Assert.Null(model.GetTypeInfo(type).Type);
type = type.SkipScoped(out _);
if (type is RefTypeSyntax refType)
{
Assert.Null(model.GetSymbolInfo(type).Symbol);
Assert.Null(model.GetTypeInfo(type).Type);
type = refType.Type;
}
Assert.Equal("R", model.GetSymbolInfo(type).Symbol.ToTestDisplayString());
Assert.Equal("R", model.GetTypeInfo(type).Type.ToTestDisplayString());
}
}
}
[Fact]
public void LocalScope_01_UsingStmt()
{
var source =
@"#pragma warning disable 219
class Program
{
static void F(ref R r)
{
using (scoped R r1 = default) {}
using (scoped ref R r2 = ref r) {}
using (scoped ref readonly R r5 = ref r) {}
}
}
ref struct R
{
public void Dispose() {}
}
";
var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10);
comp.VerifyEmitDiagnostics(
// (7,16): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater.
// using (scoped R r1 = default) {}
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "scoped").WithArguments("ref fields", "11.0").WithLocation(7, 16),
// (8,16): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater.
// using (scoped ref R r2 = ref r) {}
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "scoped").WithArguments("ref fields", "11.0").WithLocation(8, 16),
// (8,23): error CS1073: Unexpected token 'ref'
// using (scoped ref R r2 = ref r) {}
Diagnostic(ErrorCode.ERR_UnexpectedToken, "ref").WithArguments("ref").WithLocation(8, 23),
// (9,16): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater.
// using (scoped ref readonly R r5 = ref r) {}
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "scoped").WithArguments("ref fields", "11.0").WithLocation(9, 16),
// (9,23): error CS1073: Unexpected token 'ref'
// using (scoped ref readonly R r5 = ref r) {}
Diagnostic(ErrorCode.ERR_UnexpectedToken, "ref").WithArguments("ref").WithLocation(9, 23)
);
verify(comp);
comp = CreateCompilation(source);
comp.VerifyEmitDiagnostics(
// (8,23): error CS1073: Unexpected token 'ref'
// using (scoped ref R r2 = ref r) {}
Diagnostic(ErrorCode.ERR_UnexpectedToken, "ref").WithArguments("ref").WithLocation(8, 23),
// (9,23): error CS1073: Unexpected token 'ref'
// using (scoped ref readonly R r5 = ref r) {}
Diagnostic(ErrorCode.ERR_UnexpectedToken, "ref").WithArguments("ref").WithLocation(9, 23)
);
verify(comp);
static void verify(CSharpCompilation comp)
{
var tree = comp.SyntaxTrees[0];
var model = comp.GetSemanticModel(tree);
var decls = tree.GetRoot().DescendantNodes().OfType<VariableDeclaratorSyntax>().ToArray();
var locals = decls.Select(d => model.GetDeclaredSymbol(d).GetSymbol<LocalSymbol>()).ToArray();
VerifyLocalSymbol(locals[0], "scoped R r1", RefKind.None, ScopedKind.ScopedValue);
VerifyLocalSymbol(locals[1], "scoped ref R r2", RefKind.Ref, ScopedKind.ScopedRef);
VerifyLocalSymbol(locals[2], "scoped ref readonly R r5", RefKind.RefReadOnly, ScopedKind.ScopedRef);
foreach (var decl in decls)
{
var type = ((VariableDeclarationSyntax)decl.Parent).Type;
Assert.True(SyntaxFacts.IsInTypeOnlyContext(type));
Assert.True(SyntaxFacts.IsInTypeOnlyContext(type.SkipScoped(out _)));
Assert.True(SyntaxFacts.IsInTypeOnlyContext(type.SkipScoped(out _).SkipRef()));
Assert.Null(model.GetSymbolInfo(type).Symbol);
Assert.Null(model.GetTypeInfo(type).Type);
type = type.SkipScoped(out _);
if (type is RefTypeSyntax refType)
{
Assert.Null(model.GetSymbolInfo(type).Symbol);
Assert.Null(model.GetTypeInfo(type).Type);
type = refType.Type;
}
Assert.Equal("R", model.GetSymbolInfo(type).Symbol.ToTestDisplayString());
Assert.Equal("R", model.GetTypeInfo(type).Type.ToTestDisplayString());
}
}
}
[Fact]
public void LocalScope_04_UsingDecl()
{
var source =
@"using scoped s1 = default;
using ref scoped s2 = ref s1; // 1
using ref @scoped s3 = ref s1;
using scoped scoped s4 = default; // 2
using scoped ref scoped s5 = ref s1; // 3
using scoped ref @scoped s6 = ref s1; // 4
ref struct @scoped
{
public void Dispose() {}
}
";
var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10);
comp.VerifyEmitDiagnostics(
// (2,7): error CS1073: Unexpected token 'ref'
// using ref scoped s2 = ref s1; // 1
Diagnostic(ErrorCode.ERR_UnexpectedToken, "ref").WithArguments("ref").WithLocation(2, 7),
// (2,27): error CS1657: Cannot use 's1' as a ref or out value because it is a 'using variable'
// using ref scoped s2 = ref s1; // 1
Diagnostic(ErrorCode.ERR_RefReadonlyLocalCause, "s1").WithArguments("s1", "using variable").WithLocation(2, 27),
// (3,7): error CS1073: Unexpected token 'ref'
// using ref @scoped s3 = ref s1;
Diagnostic(ErrorCode.ERR_UnexpectedToken, "ref").WithArguments("ref").WithLocation(3, 7),
// (3,28): error CS1657: Cannot use 's1' as a ref or out value because it is a 'using variable'
// using ref @scoped s3 = ref s1;
Diagnostic(ErrorCode.ERR_RefReadonlyLocalCause, "s1").WithArguments("s1", "using variable").WithLocation(3, 28),
// (4,7): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater.
// using scoped scoped s4 = default; // 2
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "scoped").WithArguments("ref fields", "11.0").WithLocation(4, 7),
// (5,7): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater.
// using scoped ref scoped s5 = ref s1; // 3
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "scoped").WithArguments("ref fields", "11.0").WithLocation(5, 7),
// (5,14): error CS1073: Unexpected token 'ref'
// using scoped ref scoped s5 = ref s1; // 3
Diagnostic(ErrorCode.ERR_UnexpectedToken, "ref").WithArguments("ref").WithLocation(5, 14),
// (5,34): error CS1657: Cannot use 's1' as a ref or out value because it is a 'using variable'
// using scoped ref scoped s5 = ref s1; // 3
Diagnostic(ErrorCode.ERR_RefReadonlyLocalCause, "s1").WithArguments("s1", "using variable").WithLocation(5, 34),
// (6,7): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater.
// using scoped ref @scoped s6 = ref s1; // 4
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "scoped").WithArguments("ref fields", "11.0").WithLocation(6, 7),
// (6,14): error CS1073: Unexpected token 'ref'
// using scoped ref @scoped s6 = ref s1; // 4
Diagnostic(ErrorCode.ERR_UnexpectedToken, "ref").WithArguments("ref").WithLocation(6, 14),
// (6,35): error CS1657: Cannot use 's1' as a ref or out value because it is a 'using variable'
// using scoped ref @scoped s6 = ref s1; // 4
Diagnostic(ErrorCode.ERR_RefReadonlyLocalCause, "s1").WithArguments("s1", "using variable").WithLocation(6, 35)
);
verify(comp);
comp = CreateCompilation(source);
comp.VerifyDiagnostics(
// (2,7): error CS1073: Unexpected token 'ref'
// using ref scoped s2 = ref s1; // 1
Diagnostic(ErrorCode.ERR_UnexpectedToken, "ref").WithArguments("ref").WithLocation(2, 7),
// (2,27): error CS1657: Cannot use 's1' as a ref or out value because it is a 'using variable'
// using ref scoped s2 = ref s1; // 1
Diagnostic(ErrorCode.ERR_RefReadonlyLocalCause, "s1").WithArguments("s1", "using variable").WithLocation(2, 27),
// (3,7): error CS1073: Unexpected token 'ref'
// using ref @scoped s3 = ref s1;
Diagnostic(ErrorCode.ERR_UnexpectedToken, "ref").WithArguments("ref").WithLocation(3, 7),
// (3,28): error CS1657: Cannot use 's1' as a ref or out value because it is a 'using variable'
// using ref @scoped s3 = ref s1;
Diagnostic(ErrorCode.ERR_RefReadonlyLocalCause, "s1").WithArguments("s1", "using variable").WithLocation(3, 28),
// (5,14): error CS1073: Unexpected token 'ref'
// using scoped ref scoped s5 = ref s1; // 3
Diagnostic(ErrorCode.ERR_UnexpectedToken, "ref").WithArguments("ref").WithLocation(5, 14),
// (5,34): error CS1657: Cannot use 's1' as a ref or out value because it is a 'using variable'
// using scoped ref scoped s5 = ref s1; // 3
Diagnostic(ErrorCode.ERR_RefReadonlyLocalCause, "s1").WithArguments("s1", "using variable").WithLocation(5, 34),
// (6,14): error CS1073: Unexpected token 'ref'
// using scoped ref @scoped s6 = ref s1; // 4
Diagnostic(ErrorCode.ERR_UnexpectedToken, "ref").WithArguments("ref").WithLocation(6, 14),
// (6,35): error CS1657: Cannot use 's1' as a ref or out value because it is a 'using variable'
// using scoped ref @scoped s6 = ref s1; // 4
Diagnostic(ErrorCode.ERR_RefReadonlyLocalCause, "s1").WithArguments("s1", "using variable").WithLocation(6, 35)
);
verify(comp);
static void verify(CSharpCompilation comp)
{
var tree = comp.SyntaxTrees[0];
var model = comp.GetSemanticModel(tree);
var decls = tree.GetRoot().DescendantNodes().OfType<VariableDeclaratorSyntax>().ToArray();
var locals = decls.Select(d => model.GetDeclaredSymbol(d).GetSymbol<LocalSymbol>()).ToArray();
VerifyLocalSymbol(locals[0], "scoped s1", RefKind.None, ScopedKind.None);
VerifyLocalSymbol(locals[1], "ref scoped s2", RefKind.Ref, ScopedKind.None);
VerifyLocalSymbol(locals[2], "ref scoped s3", RefKind.Ref, ScopedKind.None);
VerifyLocalSymbol(locals[3], "scoped scoped s4", RefKind.None, ScopedKind.ScopedValue);
VerifyLocalSymbol(locals[4], "scoped ref scoped s5", RefKind.Ref, ScopedKind.ScopedRef);
VerifyLocalSymbol(locals[5], "scoped ref scoped s6", RefKind.Ref, ScopedKind.ScopedRef);
}
}
[Fact]
public void LocalScope_04_UsingStmt()
{
var source =
@"
using (scoped s1 = default)
using (ref scoped s2 = ref s1)
using (ref @scoped s3 = ref s1)
using (scoped scoped s4 = default)
using (scoped ref scoped s5 = ref s1)
using (scoped ref @scoped s6 = ref s1)
{}
ref struct @scoped
{
public void Dispose() {}
}
";
var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10);
comp.VerifyEmitDiagnostics(
// (3,12): error CS1073: Unexpected token 'ref'
// using (ref scoped s2 = ref s1)
Diagnostic(ErrorCode.ERR_UnexpectedToken, "ref").WithArguments("ref").WithLocation(3, 12),
// (3,32): error CS1657: Cannot use 's1' as a ref or out value because it is a 'using variable'
// using (ref scoped s2 = ref s1)
Diagnostic(ErrorCode.ERR_RefReadonlyLocalCause, "s1").WithArguments("s1", "using variable").WithLocation(3, 32),
// (4,16): error CS1073: Unexpected token 'ref'
// using (ref @scoped s3 = ref s1)
Diagnostic(ErrorCode.ERR_UnexpectedToken, "ref").WithArguments("ref").WithLocation(4, 16),
// (4,37): error CS1657: Cannot use 's1' as a ref or out value because it is a 'using variable'
// using (ref @scoped s3 = ref s1)
Diagnostic(ErrorCode.ERR_RefReadonlyLocalCause, "s1").WithArguments("s1", "using variable").WithLocation(4, 37),
// (5,20): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater.
// using (scoped scoped s4 = default)
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "scoped").WithArguments("ref fields", "11.0").WithLocation(5, 20),
// (6,24): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater.
// using (scoped ref scoped s5 = ref s1)
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "scoped").WithArguments("ref fields", "11.0").WithLocation(6, 24),
// (6,31): error CS1073: Unexpected token 'ref'
// using (scoped ref scoped s5 = ref s1)
Diagnostic(ErrorCode.ERR_UnexpectedToken, "ref").WithArguments("ref").WithLocation(6, 31),
// (6,51): error CS1657: Cannot use 's1' as a ref or out value because it is a 'using variable'
// using (scoped ref scoped s5 = ref s1)
Diagnostic(ErrorCode.ERR_RefReadonlyLocalCause, "s1").WithArguments("s1", "using variable").WithLocation(6, 51),
// (7,28): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater.
// using (scoped ref @scoped s6 = ref s1)
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "scoped").WithArguments("ref fields", "11.0").WithLocation(7, 28),
// (7,35): error CS1073: Unexpected token 'ref'
// using (scoped ref @scoped s6 = ref s1)
Diagnostic(ErrorCode.ERR_UnexpectedToken, "ref").WithArguments("ref").WithLocation(7, 35),
// (7,56): error CS1657: Cannot use 's1' as a ref or out value because it is a 'using variable'
// using (scoped ref @scoped s6 = ref s1)
Diagnostic(ErrorCode.ERR_RefReadonlyLocalCause, "s1").WithArguments("s1", "using variable").WithLocation(7, 56)
);
verify(comp);
comp = CreateCompilation(source);
comp.VerifyDiagnostics(
// (3,12): error CS1073: Unexpected token 'ref'
// using (ref scoped s2 = ref s1)
Diagnostic(ErrorCode.ERR_UnexpectedToken, "ref").WithArguments("ref").WithLocation(3, 12),
// (3,32): error CS1657: Cannot use 's1' as a ref or out value because it is a 'using variable'
// using (ref scoped s2 = ref s1)
Diagnostic(ErrorCode.ERR_RefReadonlyLocalCause, "s1").WithArguments("s1", "using variable").WithLocation(3, 32),
// (4,16): error CS1073: Unexpected token 'ref'
// using (ref @scoped s3 = ref s1)
Diagnostic(ErrorCode.ERR_UnexpectedToken, "ref").WithArguments("ref").WithLocation(4, 16),
// (4,37): error CS1657: Cannot use 's1' as a ref or out value because it is a 'using variable'
// using (ref @scoped s3 = ref s1)
Diagnostic(ErrorCode.ERR_RefReadonlyLocalCause, "s1").WithArguments("s1", "using variable").WithLocation(4, 37),
// (6,31): error CS1073: Unexpected token 'ref'
// using (scoped ref scoped s5 = ref s1)
Diagnostic(ErrorCode.ERR_UnexpectedToken, "ref").WithArguments("ref").WithLocation(6, 31),
// (6,51): error CS1657: Cannot use 's1' as a ref or out value because it is a 'using variable'
// using (scoped ref scoped s5 = ref s1)
Diagnostic(ErrorCode.ERR_RefReadonlyLocalCause, "s1").WithArguments("s1", "using variable").WithLocation(6, 51),
// (7,35): error CS1073: Unexpected token 'ref'
// using (scoped ref @scoped s6 = ref s1)
Diagnostic(ErrorCode.ERR_UnexpectedToken, "ref").WithArguments("ref").WithLocation(7, 35),
// (7,56): error CS1657: Cannot use 's1' as a ref or out value because it is a 'using variable'
// using (scoped ref @scoped s6 = ref s1)
Diagnostic(ErrorCode.ERR_RefReadonlyLocalCause, "s1").WithArguments("s1", "using variable").WithLocation(7, 56)
);
verify(comp);
static void verify(CSharpCompilation comp)
{
var tree = comp.SyntaxTrees[0];
var model = comp.GetSemanticModel(tree);
var decls = tree.GetRoot().DescendantNodes().OfType<VariableDeclaratorSyntax>().ToArray();
var locals = decls.Select(d => model.GetDeclaredSymbol(d).GetSymbol<LocalSymbol>()).ToArray();
VerifyLocalSymbol(locals[0], "scoped s1", RefKind.None, ScopedKind.None);
VerifyLocalSymbol(locals[1], "ref scoped s2", RefKind.Ref, ScopedKind.None);
VerifyLocalSymbol(locals[2], "ref scoped s3", RefKind.Ref, ScopedKind.None);
VerifyLocalSymbol(locals[3], "scoped scoped s4", RefKind.None, ScopedKind.ScopedValue);
VerifyLocalSymbol(locals[4], "scoped ref scoped s5", RefKind.Ref, ScopedKind.ScopedRef);
VerifyLocalSymbol(locals[5], "scoped ref scoped s6", RefKind.Ref, ScopedKind.ScopedRef);
}
}
[Fact]
public void LocalScope_06_UsingDecl()
{
var source =
@"#pragma warning disable CS0219 // The variable is assigned but its value is never used
class Program
{
static void M(R<int> r0)
{
using scoped var r1 = new R<int>();
using scoped var r3 = M(ref r0);
}
static R<int> M(ref R<int> x) => x;
}
ref struct R<T>
{
public void Dispose() {}
}
";
var comp = CreateCompilation(source);
comp.VerifyDiagnostics();
verifyModel(comp);
comp = CreateCompilation(source, parseOptions: TestOptions.RegularDefault.WithFeature("run-nullable-analysis", "never"));
verifyModel(comp);
static void verifyModel(CSharpCompilation comp)
{
var tree = comp.SyntaxTrees[0];
var model = comp.GetSemanticModel(tree);
var decls = tree.GetRoot().DescendantNodes().OfType<VariableDeclaratorSyntax>().ToArray();
var locals = decls.Select(d => model.GetDeclaredSymbol(d).GetSymbol<LocalSymbol>()).ToArray();
foreach (SourceLocalSymbol local in locals)
{
Assert.True(local.IsVar);
Assert.Equal("R<System.Int32>", local.Type.ToTestDisplayString());
}
VerifyLocalSymbol(locals[0], "scoped R<System.Int32> r1", RefKind.None, ScopedKind.ScopedValue);
VerifyLocalSymbol(locals[1], "scoped R<System.Int32> r3", RefKind.None, ScopedKind.ScopedValue);
foreach (var decl in decls)
{
var type = ((VariableDeclarationSyntax)decl.Parent).Type;
Assert.Null(model.GetSymbolInfo(type).Symbol);
Assert.Null(model.GetTypeInfo(type).Type);
type = type.SkipScoped(out _);
Assert.Equal("R<System.Int32>", model.GetSymbolInfo(type).Symbol.ToTestDisplayString());
Assert.Equal("R<System.Int32>", model.GetTypeInfo(type).Type.ToTestDisplayString());
}
}
}
[Fact]
public void LocalScope_06_UsingStmt()
{
var source =
@"#pragma warning disable CS0219 // The variable is assigned but its value is never used
class Program
{
static void M(R<int> r0)
{
using (scoped var r1 = new R<int>()) {}
using (scoped var r3 = M(ref r0)) {}
}
static R<int> M(ref R<int> x) => x;
}
ref struct R<T>
{
public void Dispose() {}
}
";
var comp = CreateCompilation(source);
comp.VerifyDiagnostics();
verifyModel(comp);
comp = CreateCompilation(source, parseOptions: TestOptions.RegularDefault.WithFeature("run-nullable-analysis", "never"));
verifyModel(comp);
static void verifyModel(CSharpCompilation comp)
{
var tree = comp.SyntaxTrees[0];
var model = comp.GetSemanticModel(tree);
var decls = tree.GetRoot().DescendantNodes().OfType<VariableDeclaratorSyntax>().ToArray();
var locals = decls.Select(d => model.GetDeclaredSymbol(d).GetSymbol<LocalSymbol>()).ToArray();
foreach (SourceLocalSymbol local in locals)
{
Assert.True(local.IsVar);
Assert.Equal("R<System.Int32>", local.Type.ToTestDisplayString());
}
VerifyLocalSymbol(locals[0], "scoped R<System.Int32> r1", RefKind.None, ScopedKind.ScopedValue);
VerifyLocalSymbol(locals[1], "scoped R<System.Int32> r3", RefKind.None, ScopedKind.ScopedValue);
foreach (var decl in decls)
{
var type = ((VariableDeclarationSyntax)decl.Parent).Type;
Assert.Null(model.GetSymbolInfo(type).Symbol);
Assert.Null(model.GetTypeInfo(type).Type);
type = type.SkipScoped(out _);
Assert.Equal("R<System.Int32>", model.GetSymbolInfo(type).Symbol.ToTestDisplayString());
Assert.Equal("R<System.Int32>", model.GetTypeInfo(type).Type.ToTestDisplayString());
}
}
}
[Fact]
public void LocalScope_10_UsingDecl_01()
{
var source =
@"{
int i = 0;
using S s1 = new S(ref i);
scoped S s2 = s1;
}
ref struct S
{
public S(ref int i) { }
public void Dispose() {}
}
";
var comp = CreateCompilation(source);
comp.VerifyDiagnostics();
}
[Fact]
public void LocalScope_10_UsingDecl_02()
{
var source =
@"{
int i = 0;
S s1 = new S(ref i);
using scoped S s2 = s1;
}
ref struct S
{
public S(ref int i) { }
public void Dispose() {}
}
";
var comp = CreateCompilation(source);
comp.VerifyDiagnostics();
}
[Fact]
public void LocalScope_10_UsingStmt_01()
{
var source =
@"{
int i = 0;
using (S s1 = new S(ref i))
{
scoped S s2 = s1;
}
}
ref struct S
{
public S(ref int i) { }
public void Dispose() {}
}
";
var comp = CreateCompilation(source);
comp.VerifyDiagnostics();
}
[Fact]
public void LocalScope_10_UsingStmt_02()
{
var source =
@"{
int i = 0;
S s1 = new S(ref i);
using (scoped S s2 = s1) {}
}
ref struct S
{
public S(ref int i) { }
public void Dispose() {}
}
";
var comp = CreateCompilation(source);
comp.VerifyDiagnostics();
}
[Fact]
public void LocalScope_12_UsingDecl()
{
var source =
@"class Program
{
static void Main()
{
int i0 = 0;
S s0 = new S(ref i0);
{
int i1 = 1;
using S s1 = new S(ref i1);
s0 = s1; // 1
}
{
using scoped S s2 = s0;
s0 = s2; // 2
}
{
using S s3 = s0;
s0 = s3;
}
}
}
ref struct S
{
public S(ref int i) { }
public void Dispose() {}
}
";
var comp = CreateCompilation(source);
comp.VerifyDiagnostics(
// (10,18): error CS8352: Cannot use variable 's1' in this context because it may expose referenced variables outside of their declaration scope
// s0 = s1; // 1
Diagnostic(ErrorCode.ERR_EscapeVariable, "s1").WithArguments("s1").WithLocation(10, 18),
// (14,18): error CS8352: Cannot use variable 's2' in this context because it may expose referenced variables outside of their declaration scope
// s0 = s2; // 2
Diagnostic(ErrorCode.ERR_EscapeVariable, "s2").WithArguments("s2").WithLocation(14, 18));
}
[Fact]
public void LocalScope_12_UsingStmt()
{
var source =
@"class Program
{
static void Main()
{
int i0 = 0;
S s0 = new S(ref i0);
{
int i1 = 1;
using (S s1 = new S(ref i1))
{
s0 = s1; // 1
}
}
{
using (scoped S s2 = s0)
{
s0 = s2; // 2
}
}
{
using (S s3 = s0)
{
s0 = s3;
}
}
}
}
ref struct S
{
public S(ref int i) { }
public void Dispose() {}
}
";
var comp = CreateCompilation(source);
comp.VerifyDiagnostics(
// (11,22): error CS8352: Cannot use variable 's1' in this context because it may expose referenced variables outside of their declaration scope
// s0 = s1; // 1
Diagnostic(ErrorCode.ERR_EscapeVariable, "s1").WithArguments("s1").WithLocation(11, 22),
// (17,22): error CS8352: Cannot use variable 's2' in this context because it may expose referenced variables outside of their declaration scope
// s0 = s2; // 2
Diagnostic(ErrorCode.ERR_EscapeVariable, "s2").WithArguments("s2").WithLocation(17, 22)
);
}
[Fact]
public void LocalScope_13_UsingDecl()
{
var source =
@"#pragma warning disable 219
class Program
{
static void F(R r)
{
using scoped R r2 = r, r5 = r;
}
}
ref struct R
{
public void Dispose() {}
}
";
var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10);
comp.VerifyEmitDiagnostics(
// (7,15): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater.
// using scoped R r2 = r, r5 = r;
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "scoped").WithArguments("ref fields", "11.0").WithLocation(7, 15)
);
verify(comp);
comp = CreateCompilation(source);
comp.VerifyEmitDiagnostics();
verify(comp);
static void verify(CSharpCompilation comp)
{
var tree = comp.SyntaxTrees[0];
var model = comp.GetSemanticModel(tree);
var decls = tree.GetRoot().DescendantNodes().OfType<VariableDeclaratorSyntax>().ToArray();
var locals = decls.Select(d => model.GetDeclaredSymbol(d).GetSymbol<LocalSymbol>()).ToArray();
VerifyLocalSymbol(locals[0], "scoped R r2", RefKind.None, ScopedKind.ScopedValue);
VerifyLocalSymbol(locals[1], "scoped R r5", RefKind.None, ScopedKind.ScopedValue);
var type = ((VariableDeclarationSyntax)decls[0].Parent).Type;
Assert.Null(model.GetTypeInfo(type).Type);
Assert.Equal("R", model.GetSymbolInfo(type.SkipScoped(out _).SkipRef()).Symbol.ToTestDisplayString());
}
}
[Fact]
public void LocalScope_13_UsingStmt()
{
var source =
@"#pragma warning disable 219
class Program
{
static void F(R r)
{
using (scoped R r2 = r, r5 = r) {}
}
}
ref struct R
{
public void Dispose() {}
}
";
var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10);
comp.VerifyEmitDiagnostics(
// (7,16): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater.
// using (scoped R r2 = r, r5 = r) {}
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "scoped").WithArguments("ref fields", "11.0").WithLocation(7, 16)
);
verify(comp);
comp = CreateCompilation(source);
comp.VerifyEmitDiagnostics();
verify(comp);
static void verify(CSharpCompilation comp)
{
var tree = comp.SyntaxTrees[0];
var model = comp.GetSemanticModel(tree);
var decls = tree.GetRoot().DescendantNodes().OfType<VariableDeclaratorSyntax>().ToArray();
var locals = decls.Select(d => model.GetDeclaredSymbol(d).GetSymbol<LocalSymbol>()).ToArray();
VerifyLocalSymbol(locals[0], "scoped R r2", RefKind.None, ScopedKind.ScopedValue);
VerifyLocalSymbol(locals[1], "scoped R r5", RefKind.None, ScopedKind.ScopedValue);
var type = ((VariableDeclarationSyntax)decls[0].Parent).Type;
Assert.Null(model.GetTypeInfo(type).Type);
Assert.Equal("R", model.GetSymbolInfo(type.SkipScoped(out _).SkipRef()).Symbol.ToTestDisplayString());
}
}
[Fact]
public void ScopedRefAndRefStructOnly_06_UsingDecl()
{
var source =
@"
class Program
{
static void Main()
{
using scoped var x1 = new R<int>();
using scoped var y1 = new S<int>();
using scoped S<int> y4 = new S<int>(), y5 = new S<int>();
}
}
ref struct R<T>
{
public void Dispose() {}
}
struct S<T> : System.IDisposable
{
public void Dispose() {}
}
";
var comp = CreateCompilation(source);
comp.VerifyDiagnostics(
// (7,22): error CS9048: The 'scoped' modifier can be used for refs and ref struct values only.
// using scoped var y1 = new S<int>();
Diagnostic(ErrorCode.ERR_ScopedRefAndRefStructOnly, "var").WithLocation(7, 22),
// (8,22): error CS9048: The 'scoped' modifier can be used for refs and ref struct values only.
// using scoped S<int> y4 = new S<int>(), y5 = new S<int>();
Diagnostic(ErrorCode.ERR_ScopedRefAndRefStructOnly, "S<int>").WithLocation(8, 22),
// (8,22): error CS9048: The 'scoped' modifier can be used for refs and ref struct values only.
// using scoped S<int> y4 = new S<int>(), y5 = new S<int>();
Diagnostic(ErrorCode.ERR_ScopedRefAndRefStructOnly, "S<int>").WithLocation(8, 22)
);
}
[Fact]
public void ScopedRefAndRefStructOnly_06_UsingStmt()
{
var source =
@"
class Program
{
static void Main()
{
using (scoped var x1 = new R<int>()) {}
using (scoped var y1 = new S<int>()) {}
using (scoped S<int> y4 = new S<int>(), y5 = new S<int>()) {}
}
}
ref struct R<T>
{
public void Dispose() {}
}
struct S<T> : System.IDisposable
{
public void Dispose() {}
}
";
var comp = CreateCompilation(source);
comp.VerifyDiagnostics(
// (7,23): error CS9048: The 'scoped' modifier can be used for refs and ref struct values only.
// using (scoped var y1 = new S<int>()) {}
Diagnostic(ErrorCode.ERR_ScopedRefAndRefStructOnly, "var").WithLocation(7, 23),
// (8,23): error CS9048: The 'scoped' modifier can be used for refs and ref struct values only.
// using (scoped S<int> y4 = new S<int>(), y5 = new S<int>()) {}
Diagnostic(ErrorCode.ERR_ScopedRefAndRefStructOnly, "S<int>").WithLocation(8, 23),
// (8,23): error CS9048: The 'scoped' modifier can be used for refs and ref struct values only.
// using (scoped S<int> y4 = new S<int>(), y5 = new S<int>()) {}
Diagnostic(ErrorCode.ERR_ScopedRefAndRefStructOnly, "S<int>").WithLocation(8, 23)
);
}
[Fact, WorkItem(63526, "https://github.com/dotnet/roslyn/issues/63526")]
public void ReturnOnlyScope_01()
{
// test that return scope is used in all return-ey locations.
var source = """
using System.Diagnostics.CodeAnalysis;
ref struct RS
{
public byte B;
[UnscopedRef]
public RSOut ToRSOut()
{
return new RSOut { RB = ref this.B };
}
}
ref struct RSOut
{
public ref byte RB;
}
class Program
{
RS M1(ref RS rs) => rs;
void M2(ref RS rs, out RSOut rs1) => rs1 = rs.ToRSOut();
RS M3(ref RS rs)
{
return rs;
}
void M4(ref RS rs, out RSOut rs1)
{
rs1 = rs.ToRSOut();
}
void localContainer()
{
#pragma warning disable 8321
RS M1(ref RS rs) => rs;
void M2(ref RS rs, out RSOut rs1) => rs1 = rs.ToRSOut();
RS M3(ref RS rs)
{
return rs;
}
void M4(ref RS rs, out RSOut rs1)
{
rs1 = rs.ToRSOut(); // 4
}
}
delegate RS ReturnsRefStruct(ref RS rs);
delegate void RefStructOut(ref RS rs, out RSOut rs1);
void lambdaContainer()
{
ReturnsRefStruct d1 = (ref RS rs) => rs;
RefStructOut d2 = (ref RS rs, out RSOut rs1) => rs1 = rs.ToRSOut();
ReturnsRefStruct d3 = (ref RS rs) =>
{
return rs;
};
RefStructOut d4 = (ref RS rs, out RSOut rs1) =>
{
rs1 = rs.ToRSOut();
};
}
}
""";
var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70);
comp.VerifyDiagnostics();
}
[Fact, WorkItem(63526, "https://github.com/dotnet/roslyn/issues/63526")]
public void ReturnOnlyScope_02()
{
var source = """
using System.Diagnostics.CodeAnalysis;
#pragma warning disable 8321 // unused local function
static bool condition() => false;
static void M1(scoped ref S p1, ref S p2) {
p2.refField = ref p1.field; // 1
p2.refField = ref p1.refField; // Okay
}
static void M2(scoped ref S p1, out S p2) {
p2 = default;
p2.refField = ref p1.field; // 2
p2.refField = ref p1.refField; // Okay
}
static void M3(out S p1, ref S p2) {
p1 = default;
p2.refField = ref p1.field; // 3
p2.refField = ref p1.refField; // 4
}
// The [UnscopedRef] moves `out` to default RSTE which is *return only*
static void M4([UnscopedRef] out S p1, ref S p2) {
p1 = default;
p2.refField = ref p1.field; // 5
p2.refField = ref p1.refField; // 6
}
static void M5(ref S p1, ref S2 p2) {
p2 = Inner1(ref p1); // 7
p2 = Inner2(ref p1); // Okay
}
static void M6(ref S p1, out S2 p2) {
p2 = Inner1(ref p1); // Okay
p2 = Inner2(ref p1); // Okay
}
static void M7(scoped ref S p1, ref S2 p2) {
p2 = Inner1(ref p1); // 8
p2 = Inner2(ref p1); // Okay
}
static S2 M8(scoped ref S p) {
if (condition()) return Inner1(ref p); // 9
if (condition()) return Inner2(ref p); // Okay
throw null!;
}
static S2 M9(ref S p) {
if (condition()) return Inner1(ref p); // Okay
if (condition()) return Inner2(ref p); // Okay
throw null!;
}
static S2 Inner1(ref S s) => new S2 { S = s };
static S2 Inner2(scoped ref S s) => new S2 { S = s };
ref struct S {
public int field;
public ref int refField;
}
ref struct S2 {
public S S;
}
""";
var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70);
comp.VerifyDiagnostics(
// (7,5): error CS8374: Cannot ref-assign 'p1.field' to 'refField' because 'p1.field' has a narrower escape scope than 'refField'.
// p2.refField = ref p1.field; // 1
Diagnostic(ErrorCode.ERR_RefAssignNarrower, "p2.refField = ref p1.field").WithArguments("refField", "p1.field").WithLocation(7, 5),
// (13,5): error CS8374: Cannot ref-assign 'p1.field' to 'refField' because 'p1.field' has a narrower escape scope than 'refField'.
// p2.refField = ref p1.field; // 2
Diagnostic(ErrorCode.ERR_RefAssignNarrower, "p2.refField = ref p1.field").WithArguments("refField", "p1.field").WithLocation(13, 5),
// (19,5): error CS8374: Cannot ref-assign 'p1.field' to 'refField' because 'p1.field' has a narrower escape scope than 'refField'.
// p2.refField = ref p1.field; // 3
Diagnostic(ErrorCode.ERR_RefAssignNarrower, "p2.refField = ref p1.field").WithArguments("refField", "p1.field").WithLocation(19, 5),
// (20,5): error CS9079: Cannot ref-assign 'p1.refField' to 'refField' because 'p1.refField' can only escape the current method through a return statement.
// p2.refField = ref p1.refField; // 4
Diagnostic(ErrorCode.ERR_RefAssignReturnOnly, "p2.refField = ref p1.refField").WithArguments("refField", "p1.refField").WithLocation(20, 5),
// (26,5): error CS9079: Cannot ref-assign 'p1.field' to 'refField' because 'p1.field' can only escape the current method through a return statement.
// p2.refField = ref p1.field; // 5
Diagnostic(ErrorCode.ERR_RefAssignReturnOnly, "p2.refField = ref p1.field").WithArguments("refField", "p1.field").WithLocation(26, 5),
// (27,5): error CS9079: Cannot ref-assign 'p1.refField' to 'refField' because 'p1.refField' can only escape the current method through a return statement.
// p2.refField = ref p1.refField; // 6
Diagnostic(ErrorCode.ERR_RefAssignReturnOnly, "p2.refField = ref p1.refField").WithArguments("refField", "p1.refField").WithLocation(27, 5),
// (31,10): error CS8347: Cannot use a result of 'Inner1(ref S)' in this context because it may expose variables referenced by parameter 's' outside of their declaration scope
// p2 = Inner1(ref p1); // 7
Diagnostic(ErrorCode.ERR_EscapeCall, "Inner1(ref p1)").WithArguments("Inner1(ref S)", "s").WithLocation(31, 10),
// (31,21): error CS9077: Cannot return a parameter by reference 'p1' through a ref parameter; it can only be returned in a return statement
// p2 = Inner1(ref p1); // 7
Diagnostic(ErrorCode.ERR_RefReturnOnlyParameter, "p1").WithArguments("p1").WithLocation(31, 21),
// (41,10): error CS8347: Cannot use a result of 'Inner1(ref S)' in this context because it may expose variables referenced by parameter 's' outside of their declaration scope
// p2 = Inner1(ref p1); // 8
Diagnostic(ErrorCode.ERR_EscapeCall, "Inner1(ref p1)").WithArguments("Inner1(ref S)", "s").WithLocation(41, 10),
// (41,21): error CS9075: Cannot return a parameter by reference 'p1' because it is scoped to the current method
// p2 = Inner1(ref p1); // 8
Diagnostic(ErrorCode.ERR_RefReturnScopedParameter, "p1").WithArguments("p1").WithLocation(41, 21),
// (46,29): error CS8347: Cannot use a result of 'Inner1(ref S)' in this context because it may expose variables referenced by parameter 's' outside of their declaration scope
// if (condition()) return Inner1(ref p); // 9
Diagnostic(ErrorCode.ERR_EscapeCall, "Inner1(ref p)").WithArguments("Inner1(ref S)", "s").WithLocation(46, 29),
// (46,40): error CS9075: Cannot return a parameter by reference 'p' because it is scoped to the current method
// if (condition()) return Inner1(ref p); // 9
Diagnostic(ErrorCode.ERR_RefReturnScopedParameter, "p").WithArguments("p").WithLocation(46, 40)
);
}
[Fact, WorkItem(63526, "https://github.com/dotnet/roslyn/issues/63526")]
public void ReturnOnlyScope_02_UnsafeContext()
{
var source = """
using System.Diagnostics.CodeAnalysis;
#pragma warning disable 8321 // unused local function
static bool condition() => false;
static unsafe void M1(scoped ref S p1, ref S p2) {
p2.refField = ref p1.field; // 1
p2.refField = ref p1.refField; // Okay
}
static unsafe void M2(scoped ref S p1, out S p2) {
p2 = default;
p2.refField = ref p1.field; // 2
p2.refField = ref p1.refField; // Okay
}
static unsafe void M3(out S p1, ref S p2) {
p1 = default;
p2.refField = ref p1.field; // 3
p2.refField = ref p1.refField; // 4
}
// The [UnscopedRef] moves `out` to default RSTE which is *return only*
static unsafe void M4([UnscopedRef] out S p1, ref S p2) {
p1 = default;
p2.refField = ref p1.field; // 5
p2.refField = ref p1.refField; // 6
}
static unsafe void M5(ref S p1, ref S2 p2) {
p2 = Inner1(ref p1); // 7
p2 = Inner2(ref p1); // Okay
}
static unsafe void M6(ref S p1, out S2 p2) {
p2 = Inner1(ref p1); // Okay
p2 = Inner2(ref p1); // Okay
}
static unsafe void M7(scoped ref S p1, ref S2 p2) {
p2 = Inner1(ref p1); // 8
p2 = Inner2(ref p1); // Okay
}
static unsafe S2 M8(scoped ref S p) {
if (condition()) return Inner1(ref p); // 9
if (condition()) return Inner2(ref p); // Okay
throw null!;
}
static S2 M9(ref S p) {
if (condition()) return Inner1(ref p); // Okay
if (condition()) return Inner2(ref p); // Okay
throw null!;
}
static S2 Inner1(ref S s) => new S2 { S = s };
static S2 Inner2(scoped ref S s) => new S2 { S = s };
ref struct S {
public int field;
public ref int refField;
}
ref struct S2 {
public S S;
}
""";
var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70, options: TestOptions.UnsafeDebugExe);
comp.VerifyDiagnostics(
// (7,5): warning CS9085: This ref-assigns 'p1.field' to 'refField' but 'p1.field' has a narrower escape scope than 'refField'.
// p2.refField = ref p1.field; // 1
Diagnostic(ErrorCode.WRN_RefAssignNarrower, "p2.refField = ref p1.field").WithArguments("refField", "p1.field").WithLocation(7, 5),
// (13,5): warning CS9085: This ref-assigns 'p1.field' to 'refField' but 'p1.field' has a narrower escape scope than 'refField'.
// p2.refField = ref p1.field; // 2
Diagnostic(ErrorCode.WRN_RefAssignNarrower, "p2.refField = ref p1.field").WithArguments("refField", "p1.field").WithLocation(13, 5),
// (19,5): warning CS9085: This ref-assigns 'p1.field' to 'refField' but 'p1.field' has a narrower escape scope than 'refField'.
// p2.refField = ref p1.field; // 3
Diagnostic(ErrorCode.WRN_RefAssignNarrower, "p2.refField = ref p1.field").WithArguments("refField", "p1.field").WithLocation(19, 5),
// (20,5): warning CS9093: This ref-assigns 'p1.refField' to 'refField' but 'p1.refField' can only escape the current method through a return statement.
// p2.refField = ref p1.refField; // 4
Diagnostic(ErrorCode.WRN_RefAssignReturnOnly, "p2.refField = ref p1.refField").WithArguments("refField", "p1.refField").WithLocation(20, 5),
// (26,5): warning CS9093: This ref-assigns 'p1.field' to 'refField' but 'p1.field' can only escape the current method through a return statement.
// p2.refField = ref p1.field; // 5
Diagnostic(ErrorCode.WRN_RefAssignReturnOnly, "p2.refField = ref p1.field").WithArguments("refField", "p1.field").WithLocation(26, 5),
// (27,5): warning CS9093: This ref-assigns 'p1.refField' to 'refField' but 'p1.refField' can only escape the current method through a return statement.
// p2.refField = ref p1.refField; // 6
Diagnostic(ErrorCode.WRN_RefAssignReturnOnly, "p2.refField = ref p1.refField").WithArguments("refField", "p1.refField").WithLocation(27, 5),
// (31,21): warning CS9094: This returns a parameter by reference 'p1' through a ref parameter; but it can only safely be returned in a return statement
// p2 = Inner1(ref p1); // 7
Diagnostic(ErrorCode.WRN_RefReturnOnlyParameter, "p1").WithArguments("p1").WithLocation(31, 21),
// (41,21): warning CS9088: This returns a parameter by reference 'p1' but it is scoped to the current method
// p2 = Inner1(ref p1); // 8
Diagnostic(ErrorCode.WRN_RefReturnScopedParameter, "p1").WithArguments("p1").WithLocation(41, 21),
// (46,40): warning CS9088: This returns a parameter by reference 'p' but it is scoped to the current method
// if (condition()) return Inner1(ref p); // 9
Diagnostic(ErrorCode.WRN_RefReturnScopedParameter, "p").WithArguments("p").WithLocation(46, 40)
);
}
[Fact, WorkItem(63526, "https://github.com/dotnet/roslyn/issues/63526")]
public void ReturnOnlyScope_03()
{
var source = """
using System.Diagnostics.CodeAnalysis;
#pragma warning disable 8321 // unused local function
ref struct S2 {
public S S;
}
ref struct S {
public int field;
public ref int refField;
void M1(ref S p) {
p.refField = ref this.field; // 1
p.refField = ref this.refField; // Okay
}
[UnscopedRef]
void M2(ref S p) {
p.refField = ref this.field; // 2
p.refField = ref this.refField; // Okay
}
[UnscopedRef]
void M3(out S p) {
p = default;
p.refField = ref this.field; // Okay (was 3)
p.refField = ref this.refField; // Okay
}
void M4(ref S2 p) {
p = Inner1(ref this); // 4
p = Inner2(ref this); // Okay
}
void M5(out S2 p) {
p = Inner1(ref this); // 5
p = Inner2(ref this); // Okay
}
static S2 Inner1(ref S s) => new S2 { S = s };
static S2 Inner2(scoped ref S s) => new S2 { S = s };
}
""";
var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70);
comp.VerifyDiagnostics(
// (13,9): error CS8374: Cannot ref-assign 'this.field' to 'refField' because 'this.field' has a narrower escape scope than 'refField'.
// p.refField = ref this.field; // 1
Diagnostic(ErrorCode.ERR_RefAssignNarrower, "p.refField = ref this.field").WithArguments("refField", "this.field").WithLocation(13, 9),
// (19,9): error CS9079: Cannot ref-assign 'this.field' to 'refField' because 'this.field' can only escape the current method through a return statement.
// p.refField = ref this.field; // 2
Diagnostic(ErrorCode.ERR_RefAssignReturnOnly, "p.refField = ref this.field").WithArguments("refField", "this.field").WithLocation(19, 9),
// (31,13): error CS8347: Cannot use a result of 'S.Inner1(ref S)' in this context because it may expose variables referenced by parameter 's' outside of their declaration scope
// p = Inner1(ref this); // 4
Diagnostic(ErrorCode.ERR_EscapeCall, "Inner1(ref this)").WithArguments("S.Inner1(ref S)", "s").WithLocation(31, 13),
// (31,24): error CS8170: Struct members cannot return 'this' or other instance members by reference
// p = Inner1(ref this); // 4
Diagnostic(ErrorCode.ERR_RefReturnStructThis, "this").WithLocation(31, 24),
// (36,13): error CS8347: Cannot use a result of 'S.Inner1(ref S)' in this context because it may expose variables referenced by parameter 's' outside of their declaration scope
// p = Inner1(ref this); // 5
Diagnostic(ErrorCode.ERR_EscapeCall, "Inner1(ref this)").WithArguments("S.Inner1(ref S)", "s").WithLocation(36, 13),
// (36,24): error CS8170: Struct members cannot return 'this' or other instance members by reference
// p = Inner1(ref this); // 5
Diagnostic(ErrorCode.ERR_RefReturnStructThis, "this").WithLocation(36, 24));
}
[Fact]
public void ReturnOnlyScope_03_UnsafeContext()
{
var source = """
using System.Diagnostics.CodeAnalysis;
#pragma warning disable 8321 // unused local function
ref struct S2 {
public S S;
}
unsafe ref struct S {
public int field;
public ref int refField;
void M1(ref S p) {
p.refField = ref this.field; // 1
p.refField = ref this.refField; // Okay
}
[UnscopedRef]
void M2(ref S p) {
p.refField = ref this.field; // 2
p.refField = ref this.refField; // Okay
}
[UnscopedRef]
void M3(out S p) {
p = default;
p.refField = ref this.field; // Okay (was 3)
p.refField = ref this.refField; // Okay
}
void M4(ref S2 p) {
p = Inner1(ref this); // 4
p = Inner2(ref this); // Okay
}
void M5(out S2 p) {
p = Inner1(ref this); // 5
p = Inner2(ref this); // Okay
}
static S2 Inner1(ref S s) => new S2 { S = s };
static S2 Inner2(scoped ref S s) => new S2 { S = s };
}
""";
var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70, options: TestOptions.UnsafeDebugDll);
comp.VerifyDiagnostics(
// (13,9): warning CS9085: This ref-assigns 'this.field' to 'refField' but 'this.field' has a narrower escape scope than 'refField'.
// p.refField = ref this.field; // 1
Diagnostic(ErrorCode.WRN_RefAssignNarrower, "p.refField = ref this.field").WithArguments("refField", "this.field").WithLocation(13, 9),
// (19,9): warning CS9093: This ref-assigns 'this.field' to 'refField' but 'this.field' can only escape the current method through a return statement.
// p.refField = ref this.field; // 2
Diagnostic(ErrorCode.WRN_RefAssignReturnOnly, "p.refField = ref this.field").WithArguments("refField", "this.field").WithLocation(19, 9),
// (31,24): warning CS9084: Struct member returns 'this' or other instance members by reference
// p = Inner1(ref this); // 4
Diagnostic(ErrorCode.WRN_RefReturnStructThis, "this").WithLocation(31, 24),
// (36,24): warning CS9084: Struct member returns 'this' or other instance members by reference
// p = Inner1(ref this); // 5
Diagnostic(ErrorCode.WRN_RefReturnStructThis, "this").WithLocation(36, 24));
}
[Fact]
public void ReturnOnlyScope_04()
{
// This shows that constructors end up being less "capable" than factory methods.
// We might want to adjust the rules for 'out' parameters (including 'this' in constructors).
// https://github.com/dotnet/roslyn/issues/64155
var source = """
ref struct ByteContainer
{
public byte B;
}
ref struct RefByteContainer
{
public ref byte RB;
public RefByteContainer(ref ByteContainer bc)
{
RB = ref bc.B; // 1
}
public RefByteContainer Create(ref ByteContainer bc)
{
return new RefByteContainer { RB = ref bc.B }; // ok
}
}
""";
var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70);
comp.VerifyDiagnostics();
}
[Fact, WorkItem(63526, "https://github.com/dotnet/roslyn/issues/63526")]
public void ReturnOnlyScope_UnsafeStatement()
{
var source = """
#pragma warning disable 8321 // unused local function
static void M1(scoped ref S p1, ref S p2, ref S p3)
{
unsafe
{
p2.refField = ref p1.field; // 1
}
{
p3.refField = ref p1.field; // 2
}
}
ref struct S
{
public int field;
public ref int refField;
}
""";
var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70, options: TestOptions.UnsafeReleaseExe);
comp.VerifyDiagnostics(
// (6,9): warning CS9085: This ref-assigns 'p1.field' to 'refField' but 'p1.field' has a narrower escape scope than 'refField'.
// p2.refField = ref p1.field; // 1
Diagnostic(ErrorCode.WRN_RefAssignNarrower, "p2.refField = ref p1.field").WithArguments("refField", "p1.field").WithLocation(6, 9),
// (9,9): error CS8374: Cannot ref-assign 'p1.field' to 'refField' because 'p1.field' has a narrower escape scope than 'refField'.
// p3.refField = ref p1.field; // 1
Diagnostic(ErrorCode.ERR_RefAssignNarrower, "p3.refField = ref p1.field").WithArguments("refField", "p1.field").WithLocation(9, 9));
}
/// <summary>
/// Validate that this is properly represented as an out parameter in a constructor and
/// can capture ref as ref.
/// </summary>
[Fact]
public void OutReturnOnly_Ctor1()
{
var source = """
ref struct RS
{
ref int field;
public RS(ref int i)
{
field = ref i;
}
static RS M1(ref int i) => new RS(ref i);
static RS M2()
{
int i = 0;
return new RS(ref i);
}
}
""";
var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70);
comp.VerifyDiagnostics(
// (13,16): error CS8347: Cannot use a result of 'RS.RS(ref int)' in this context because it may expose variables referenced by parameter 'i' outside of their declaration scope
// return new RS(ref i);
Diagnostic(ErrorCode.ERR_EscapeCall, "new RS(ref i)").WithArguments("RS.RS(ref int)", "i").WithLocation(13, 16),
// (13,27): error CS8168: Cannot return local 'i' by reference because it is not a ref local
// return new RS(ref i);
Diagnostic(ErrorCode.ERR_RefReturnLocal, "i").WithArguments("i").WithLocation(13, 27));
}
/// <summary>
/// Out and ref have different return scopes
/// </summary>
[Fact]
public void OutReturnOnly_1()
{
var source = """
ref struct RS
{
ref int field;
public RS(ref int i)
{
field = ref i;
}
static void M1(ref int i, ref RS rs) => rs = new RS(ref i); // 1
static void M2(ref int i, out RS rs) => rs = new RS(ref i);
}
""";
var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70);
comp.VerifyDiagnostics(
// (9,50): error CS8347: Cannot use a result of 'RS.RS(ref int)' in this context because it may expose variables referenced by parameter 'i' outside of their declaration scope
// static void M1(ref int i, ref RS rs) => rs = new RS(ref i); // 1
Diagnostic(ErrorCode.ERR_EscapeCall, "new RS(ref i)").WithArguments("RS.RS(ref int)", "i").WithLocation(9, 50),
// (9,61): error CS9077: Cannot return a parameter by reference 'i' through a ref parameter; it can only be returned in a return statement
// static void M1(ref int i, ref RS rs) => rs = new RS(ref i); // 1
Diagnostic(ErrorCode.ERR_RefReturnOnlyParameter, "i").WithArguments("i").WithLocation(9, 61));
}
/// <summary>
/// Out and in have different return scopes
/// </summary>
[Fact]
public void OutReturnOnly_2()
{
var source = """
readonly ref struct RS
{
readonly ref readonly int field;
public RS(in int i)
{
field = ref i;
}
static void M1(in int i, ref RS rs) => rs = new RS(in i); // 1
static void M2(in int i, out RS rs) => rs = new RS(in i);
}
""";
var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70);
comp.VerifyDiagnostics(
// (9,49): error CS8347: Cannot use a result of 'RS.RS(in int)' in this context because it may expose variables referenced by parameter 'i' outside of their declaration scope
// static void M1(in int i, ref RS rs) => rs = new RS(in i); // 1
Diagnostic(ErrorCode.ERR_EscapeCall, "new RS(in i)").WithArguments("RS.RS(in int)", "i").WithLocation(9, 49),
// (9,59): error CS9077: Cannot return a parameter by reference 'i' through a ref parameter; it can only be returned in a return statement
// static void M1(in int i, ref RS rs) => rs = new RS(in i); // 1
Diagnostic(ErrorCode.ERR_RefReturnOnlyParameter, "i").WithArguments("i").WithLocation(9, 59));
}
/// <summary>
/// Out and ref have different return scopes
/// </summary>
[Fact]
public void OutReturnOnly_3()
{
var source = """
using System.Diagnostics.CodeAnalysis;
ref struct RS
{
int field;
ref int refField;
public RS(ref int i)
{
refField = ref i;
}
static void M1(ref RS i, ref RS rs) => rs = new RS(ref i.field); // 1
static void M2(ref RS i, out RS rs) => rs = new RS(ref i.field);
static void M3(ref RS i, [UnscopedRef] out RS rs) => rs = new RS(ref i.field);
}
""";
var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70);
comp.VerifyDiagnostics(
// (11,49): error CS8347: Cannot use a result of 'RS.RS(ref int)' in this context because it may expose variables referenced by parameter 'i' outside of their declaration scope
// static void M1(ref RS i, ref RS rs) => rs = new RS(ref i.field); // 1
Diagnostic(ErrorCode.ERR_EscapeCall, "new RS(ref i.field)").WithArguments("RS.RS(ref int)", "i").WithLocation(11, 49),
// (11,60): error CS9078: Cannot return by reference a member of parameter 'i' through a ref parameter; it can only be returned in a return statement
// static void M1(ref RS i, ref RS rs) => rs = new RS(ref i.field); // 1
Diagnostic(ErrorCode.ERR_RefReturnOnlyParameter2, "i").WithArguments("i").WithLocation(11, 60));
}
[Fact]
[WorkItem(62094, "https://github.com/dotnet/roslyn/issues/62094")]
public void OutReturnOnly_4()
{
var source = """
ref struct R
{
public R(ref int i) { }
}
class Program
{
static void F0(ref R a, out R b)
{
b = a;
}
static void F1(ref R x)
{
int i = 1;
R y = new R(ref i);
F0(ref x, out y);
}
}
""";
var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70);
comp.VerifyDiagnostics();
}
[Fact]
public void OutReturnOnly_5()
{
var source = """
ref struct R
{
public R(ref int i) { }
}
class Program
{
public static void F1(R a, out R d) => throw null;
public static void F2(ref R a, out R d) => throw null;
public static void F3(in R a, out R d) => throw null;
public static void F4(scoped ref R a, out R d) => throw null;
public static void F5(scoped in R a, out R d) => throw null;
public void Test()
{
R local = default;
F1(local, out local);
F2(ref local, out local); // 1
F3(in local, out local); // 2
F4(ref local, out local);
F5(in local, out local);
}
}
""";
var comp = CreateCompilation(new[] { source, UnscopedRefAttributeDefinition }, targetFramework: TargetFramework.Net70);
comp.VerifyDiagnostics(
// (18,9): error CS8350: This combination of arguments to 'Program.F2(ref R, out R)' is disallowed because it may expose variables referenced by parameter 'a' outside of their declaration scope
// F2(ref local, out local); // 1
Diagnostic(ErrorCode.ERR_CallArgMixing, "F2(ref local, out local)").WithArguments("Program.F2(ref R, out R)", "a").WithLocation(18, 9),
// (18,16): error CS8168: Cannot return local 'local' by reference because it is not a ref local
// F2(ref local, out local); // 1
Diagnostic(ErrorCode.ERR_RefReturnLocal, "local").WithArguments("local").WithLocation(18, 16),
// (19,9): error CS8350: This combination of arguments to 'Program.F3(in R, out R)' is disallowed because it may expose variables referenced by parameter 'a' outside of their declaration scope
// F3(in local, out local); // 2
Diagnostic(ErrorCode.ERR_CallArgMixing, "F3(in local, out local)").WithArguments("Program.F3(in R, out R)", "a").WithLocation(19, 9),
// (19,15): error CS8168: Cannot return local 'local' by reference because it is not a ref local
// F3(in local, out local); // 2
Diagnostic(ErrorCode.ERR_RefReturnLocal, "local").WithArguments("local").WithLocation(19, 15)
);
}
[WorkItem(64720, "https://github.com/dotnet/roslyn/issues/64720")]
[ConditionalTheory(typeof(CoreClrOnly))]
[InlineData("ref")]
[InlineData("ref readonly")]
public void FieldInitializer_01(string refModifier)
{
var sourceA =
$@"ref struct R
{{
public static byte S = 1;
public {refModifier} byte F = ref S;
public R() {{ }}
}}";
var sourceB =
@"using System;
class Program
{
static void Main()
{
var r = new R();
Console.WriteLine(r.F);
R.S++;
Console.WriteLine(r.F);
}
}";
var comp = CreateCompilation(new[] { sourceA, sourceB }, targetFramework: TargetFramework.Net70, options: TestOptions.ReleaseExe);
comp.VerifyEmitDiagnostics();
var verifier = CompileAndVerify(comp, expectedOutput:
@"1
2
");
verifier.VerifyIL("R..ctor",
$@"{{
// Code size 12 (0xc)
.maxstack 2
IL_0000: ldarg.0
IL_0001: ldsflda ""byte R.S""
IL_0006: stfld ""{refModifier} byte R.F""
IL_000b: ret
}}
");
}
[WorkItem(64720, "https://github.com/dotnet/roslyn/issues/64720")]
[ConditionalFact(typeof(CoreClrOnly))]
public void FieldInitializer_02A()
{
var source =
@"using System;
ref struct R
{
public ref byte _f1 = ref F(stackalloc byte[1]);
public ref readonly byte _f2 = ref F(stackalloc byte[1]);
public R(object o) { }
static ref byte F(Span<byte> s) => ref _s;
public static byte _s;
}";
var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70);
comp.VerifyEmitDiagnostics(
// (4,31): error CS8347: Cannot use a result of 'R.F(Span<byte>)' in this context because it may expose variables referenced by parameter 's' outside of their declaration scope
// public ref byte _f1 = ref F(stackalloc byte[1]);
Diagnostic(ErrorCode.ERR_EscapeCall, "F(stackalloc byte[1])").WithArguments("R.F(System.Span<byte>)", "s").WithLocation(4, 31),
// (4,33): error CS8353: A result of a stackalloc expression of type 'Span<byte>' cannot be used in this context because it may be exposed outside of the containing method
// public ref byte _f1 = ref F(stackalloc byte[1]);
Diagnostic(ErrorCode.ERR_EscapeStackAlloc, "stackalloc byte[1]").WithArguments("System.Span<byte>").WithLocation(4, 33),
// (5,40): error CS8347: Cannot use a result of 'R.F(Span<byte>)' in this context because it may expose variables referenced by parameter 's' outside of their declaration scope
// public ref readonly byte _f2 = ref F(stackalloc byte[1]);
Diagnostic(ErrorCode.ERR_EscapeCall, "F(stackalloc byte[1])").WithArguments("R.F(System.Span<byte>)", "s").WithLocation(5, 40),
// (5,42): error CS8353: A result of a stackalloc expression of type 'Span<byte>' cannot be used in this context because it may be exposed outside of the containing method
// public ref readonly byte _f2 = ref F(stackalloc byte[1]);
Diagnostic(ErrorCode.ERR_EscapeStackAlloc, "stackalloc byte[1]").WithArguments("System.Span<byte>").WithLocation(5, 42));
}
// Similar to above but with scoped parameter.
[WorkItem(64720, "https://github.com/dotnet/roslyn/issues/64720")]
[ConditionalFact(typeof(CoreClrOnly))]
public void FieldInitializer_02B()
{
var source =
@"using System;
ref struct R
{
public ref byte _f1 = ref F(stackalloc byte[1]);
public ref readonly byte _f2 = ref F(stackalloc byte[1]);
public R(object o) { }
static ref byte F(scoped Span<byte> s) => ref _s;
public static byte _s = 1;
}
class Program
{
static void Main()
{
var r = new R(null);
Console.WriteLine((r._f1, r._f2));
R._s = 2;
Console.WriteLine((r._f1, r._f2));
}
}";
var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70, options: TestOptions.ReleaseExe);
comp.VerifyEmitDiagnostics();
var verifier = CompileAndVerify(comp, verify: Verification.Skipped, expectedOutput:
@"(1, 1)
(2, 2)
");
verifier.VerifyIL("R..ctor(object)",
@"{
// Code size 47 (0x2f)
.maxstack 2
.locals init (System.Span<byte> V_0)
IL_0000: ldc.i4.1
IL_0001: conv.u
IL_0002: localloc
IL_0004: ldc.i4.1
IL_0005: newobj ""System.Span<byte>..ctor(void*, int)""
IL_000a: stloc.0
IL_000b: ldarg.0
IL_000c: ldloc.0
IL_000d: call ""ref byte R.F(scoped System.Span<byte>)""
IL_0012: stfld ""ref byte R._f1""
IL_0017: ldc.i4.1
IL_0018: conv.u
IL_0019: localloc
IL_001b: ldc.i4.1
IL_001c: newobj ""System.Span<byte>..ctor(void*, int)""
IL_0021: stloc.0
IL_0022: ldarg.0
IL_0023: ldloc.0
IL_0024: call ""ref byte R.F(scoped System.Span<byte>)""
IL_0029: stfld ""ref readonly byte R._f2""
IL_002e: ret
}");
}
[WorkItem(64725, "https://github.com/dotnet/roslyn/issues/64725")]
[ConditionalFact(typeof(CoreClrOnly))]
public void FieldInitializer_03()
{
var source =
@"#pragma warning disable 414
ref struct R
{
ref int _f1 = 1;
ref readonly int _f2 = 2;
public R() { }
}";
var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70);
comp.VerifyEmitDiagnostics(
// (4,17): error CS8172: Cannot initialize a by-reference variable with a value
// ref int _f1 = 1;
Diagnostic(ErrorCode.ERR_InitializeByReferenceVariableWithValue, "= 1").WithLocation(4, 17),
// (4,19): error CS1510: A ref or out value must be an assignable variable
// ref int _f1 = 1;
Diagnostic(ErrorCode.ERR_RefLvalueExpected, "1").WithLocation(4, 19),
// (5,26): error CS8172: Cannot initialize a by-reference variable with a value
// ref readonly int _f2 = 2;
Diagnostic(ErrorCode.ERR_InitializeByReferenceVariableWithValue, "= 2").WithLocation(5, 26),
// (5,28): error CS8156: An expression cannot be used in this context because it may not be passed or returned by reference
// ref readonly int _f2 = 2;
Diagnostic(ErrorCode.ERR_RefReturnLvalueExpected, "2").WithLocation(5, 28));
}
[WorkItem(64725, "https://github.com/dotnet/roslyn/issues/64725")]
[ConditionalFact(typeof(CoreClrOnly))]
public void FieldInitializer_04()
{
var source =
@"using System;
ref struct R
{
ref byte _f1 = F(stackalloc byte[1]);
ref readonly byte _f2 = F(stackalloc byte[1]);
public R() { }
static ref T F<T>(Span<T> s) => throw null;
}";
var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70);
comp.VerifyEmitDiagnostics(
// (4,18): error CS8172: Cannot initialize a by-reference variable with a value
// ref byte _f1 = F(stackalloc byte[1]);
Diagnostic(ErrorCode.ERR_InitializeByReferenceVariableWithValue, "= F(stackalloc byte[1])").WithLocation(4, 18),
// (4,20): error CS8347: Cannot use a result of 'R.F<byte>(Span<byte>)' in this context because it may expose variables referenced by parameter 's' outside of their declaration scope
// ref byte _f1 = F(stackalloc byte[1]);
Diagnostic(ErrorCode.ERR_EscapeCall, "F(stackalloc byte[1])").WithArguments("R.F<byte>(System.Span<byte>)", "s").WithLocation(4, 20),
// (4,22): error CS8353: A result of a stackalloc expression of type 'Span<byte>' cannot be used in this context because it may be exposed outside of the containing method
// ref byte _f1 = F(stackalloc byte[1]);
Diagnostic(ErrorCode.ERR_EscapeStackAlloc, "stackalloc byte[1]").WithArguments("System.Span<byte>").WithLocation(4, 22),
// (5,27): error CS8172: Cannot initialize a by-reference variable with a value
// ref readonly byte _f2 = F(stackalloc byte[1]);
Diagnostic(ErrorCode.ERR_InitializeByReferenceVariableWithValue, "= F(stackalloc byte[1])").WithLocation(5, 27),
// (5,29): error CS8347: Cannot use a result of 'R.F<byte>(Span<byte>)' in this context because it may expose variables referenced by parameter 's' outside of their declaration scope
// ref readonly byte _f2 = F(stackalloc byte[1]);
Diagnostic(ErrorCode.ERR_EscapeCall, "F(stackalloc byte[1])").WithArguments("R.F<byte>(System.Span<byte>)", "s").WithLocation(5, 29),
// (5,31): error CS8353: A result of a stackalloc expression of type 'Span<byte>' cannot be used in this context because it may be exposed outside of the containing method
// ref readonly byte _f2 = F(stackalloc byte[1]);
Diagnostic(ErrorCode.ERR_EscapeStackAlloc, "stackalloc byte[1]").WithArguments("System.Span<byte>").WithLocation(5, 31));
}
[WorkItem(64725, "https://github.com/dotnet/roslyn/issues/64725")]
[ConditionalFact(typeof(CoreClrOnly))]
public void FieldInitializer_05()
{
var source =
@"using System;
ref struct R
{
ref readonly Span<int> _s = ref F(stackalloc int[1]);
public R() { }
static ref readonly Span<T> F<T>(in Span<T> s) => ref s;
}";
var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70);
comp.VerifyEmitDiagnostics(
// (4,5): error CS9050: A ref field cannot refer to a ref struct.
// ref readonly Span<int> _s = ref F(stackalloc int[1]);
Diagnostic(ErrorCode.ERR_RefFieldCannotReferToRefStruct, "ref readonly Span<int>").WithLocation(4, 5),
// (4,37): error CS8347: Cannot use a result of 'R.F<int>(in Span<int>)' in this context because it may expose variables referenced by parameter 's' outside of their declaration scope
// ref readonly Span<int> _s = ref F(stackalloc int[1]);
Diagnostic(ErrorCode.ERR_EscapeCall, "F(stackalloc int[1])").WithArguments("R.F<int>(in System.Span<int>)", "s").WithLocation(4, 37),
// (4,39): error CS8156: An expression cannot be used in this context because it may not be passed or returned by reference
// ref readonly Span<int> _s = ref F(stackalloc int[1]);
Diagnostic(ErrorCode.ERR_RefReturnLvalueExpected, "stackalloc int[1]").WithLocation(4, 39));
}
[WorkItem(64720, "https://github.com/dotnet/roslyn/issues/64720")]
[ConditionalFact(typeof(CoreClrOnly))]
public void FieldInitializer_06A()
{
var source =
@"ref struct R
{
ref byte _f1 = ref F<byte>(out var b1);
ref readonly byte _f2 = ref F<byte>(out var b2);
public R() { }
static ref T F<T>(out T t)
{
throw null;
}
}";
var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70);
comp.VerifyEmitDiagnostics();
}
// Similar to above but with [UnscopedRef] out parameter.
[WorkItem(64720, "https://github.com/dotnet/roslyn/issues/64720")]
[ConditionalFact(typeof(CoreClrOnly))]
public void FieldInitializer_06B()
{
var source =
@"using System.Diagnostics.CodeAnalysis;
ref struct R
{
ref byte _f1 = ref F<byte>(out var b1); // 1
ref readonly byte _f2 = ref F<byte>(out var b2); // 2
public R() { }
static ref T F<T>([UnscopedRef] out T t)
{
t = default;
return ref t;
}
}";
var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70);
comp.VerifyEmitDiagnostics(
// (4,24): error CS8347: Cannot use a result of 'R.F<byte>(out byte)' in this context because it may expose variables referenced by parameter 't' outside of their declaration scope
// ref byte _f1 = ref F<byte>(out var b1); // 1
Diagnostic(ErrorCode.ERR_EscapeCall, "F<byte>(out var b1)").WithArguments("R.F<byte>(out byte)", "t").WithLocation(4, 24),
// (4,36): error CS8168: Cannot return local 'b1' by reference because it is not a ref local
// ref byte _f1 = ref F<byte>(out var b1); // 1
Diagnostic(ErrorCode.ERR_RefReturnLocal, "var b1").WithArguments("b1").WithLocation(4, 36),
// (5,33): error CS8347: Cannot use a result of 'R.F<byte>(out byte)' in this context because it may expose variables referenced by parameter 't' outside of their declaration scope
// ref readonly byte _f2 = ref F<byte>(out var b2); // 2
Diagnostic(ErrorCode.ERR_EscapeCall, "F<byte>(out var b2)").WithArguments("R.F<byte>(out byte)", "t").WithLocation(5, 33),
// (5,45): error CS8168: Cannot return local 'b2' by reference because it is not a ref local
// ref readonly byte _f2 = ref F<byte>(out var b2); // 2
Diagnostic(ErrorCode.ERR_RefReturnLocal, "var b2").WithArguments("b2").WithLocation(5, 45));
}
[WorkItem(64720, "https://github.com/dotnet/roslyn/issues/64720")]
[ConditionalFact(typeof(CoreClrOnly))]
public void FieldInitializer_07()
{
var source =
@"using System;
ref struct R
{
public ref int F1 = ref C.Instance.F();
public ref readonly int F2;
public R(object obj)
{
F2 = ref F1;
}
}
class C
{
public static C Instance = new C();
int _b = 1;
public ref int F() => ref _b;
static void Main()
{
var r = new R(null);
Instance._b += 2;
Console.WriteLine((r.F1, r.F2));
}
}";
var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70, options: TestOptions.ReleaseExe);
comp.VerifyEmitDiagnostics();
var verifier = CompileAndVerify(comp, expectedOutput: "(3, 3)");
verifier.VerifyIL("R..ctor(object)",
@"{
// Code size 29 (0x1d)
.maxstack 2
IL_0000: ldarg.0
IL_0001: ldsfld ""C C.Instance""
IL_0006: callvirt ""ref int C.F()""
IL_000b: stfld ""ref int R.F1""
IL_0010: ldarg.0
IL_0011: ldarg.0
IL_0012: ldfld ""ref int R.F1""
IL_0017: stfld ""ref readonly int R.F2""
IL_001c: ret
}
");
var tree = comp.SyntaxTrees[0];
var model = comp.GetSemanticModel(tree);
var fieldInitializerSyntax = tree.GetRoot().DescendantNodes().OfType<EqualsValueClauseSyntax>().First();
var symbol = model.GetDeclaredSymbol(fieldInitializerSyntax.Parent);
Assert.Equal("ref System.Int32 R.F1", symbol.ToTestDisplayString());
var fieldInitializerOperation = (Microsoft.CodeAnalysis.Operations.IFieldInitializerOperation)model.GetOperation(fieldInitializerSyntax);
OperationTreeVerifier.Verify(
@"IFieldInitializerOperation (Field: ref System.Int32 R.F1) (OperationKind.FieldInitializer, Type: null) (Syntax: '= ref C.Instance.F()')
IInvocationOperation ( ref System.Int32 C.F()) (OperationKind.Invocation, Type: System.Int32) (Syntax: 'C.Instance.F()')
Instance Receiver:
IFieldReferenceOperation: C C.Instance (Static) (OperationKind.FieldReference, Type: C) (Syntax: 'C.Instance')
Instance Receiver:
null
Arguments(0)
",
OperationTreeVerifier.GetOperationTree(comp, fieldInitializerOperation));
var controlFlowGraph = Microsoft.CodeAnalysis.FlowAnalysis.ControlFlowGraph.Create(fieldInitializerOperation);
ControlFlowGraphVerifier.VerifyGraph(comp,
@" Block[B0] - Entry
Statements (0)
Next (Regular) Block[B1]
Block[B1] - Block
Predecessors: [B0]
Statements (1)
ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: System.Int32, IsImplicit) (Syntax: '= ref C.Instance.F()')
Left:
IFieldReferenceOperation: ref System.Int32 R.F1 (OperationKind.FieldReference, Type: System.Int32, IsImplicit) (Syntax: '= ref C.Instance.F()')
Instance Receiver:
IInstanceReferenceOperation (ReferenceKind: ContainingTypeInstance) (OperationKind.InstanceReference, Type: R, IsImplicit) (Syntax: '= ref C.Instance.F()')
Right:
IInvocationOperation ( ref System.Int32 C.F()) (OperationKind.Invocation, Type: System.Int32) (Syntax: 'C.Instance.F()')
Instance Receiver:
IFieldReferenceOperation: C C.Instance (Static) (OperationKind.FieldReference, Type: C) (Syntax: 'C.Instance')
Instance Receiver:
null
Arguments(0)
Next (Regular) Block[B2]
Block[B2] - Exit
Predecessors: [B1]
Statements (0)
",
controlFlowGraph, symbol);
var constructorSyntax = tree.GetRoot().DescendantNodes().OfType<ConstructorDeclarationSyntax>().Single();
symbol = model.GetDeclaredSymbol(constructorSyntax);
Assert.Equal("R..ctor(System.Object obj)", symbol.ToTestDisplayString());
var constructorOperation = (Microsoft.CodeAnalysis.Operations.IConstructorBodyOperation)model.GetOperation(constructorSyntax);
OperationTreeVerifier.Verify(
@"IConstructorBodyOperation (OperationKind.ConstructorBody, Type: null) (Syntax: 'public R(ob ... }')
Initializer:
null
BlockBody:
IBlockOperation (1 statements) (OperationKind.Block, Type: null) (Syntax: '{ ... }')
IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'F2 = ref F1;')
Expression:
ISimpleAssignmentOperation (IsRef) (OperationKind.SimpleAssignment, Type: System.Int32) (Syntax: 'F2 = ref F1')
Left:
IFieldReferenceOperation: ref readonly System.Int32 R.F2 (OperationKind.FieldReference, Type: System.Int32) (Syntax: 'F2')
Instance Receiver:
IInstanceReferenceOperation (ReferenceKind: ContainingTypeInstance) (OperationKind.InstanceReference, Type: R, IsImplicit) (Syntax: 'F2')
Right:
IFieldReferenceOperation: ref System.Int32 R.F1 (OperationKind.FieldReference, Type: System.Int32) (Syntax: 'F1')
Instance Receiver:
IInstanceReferenceOperation (ReferenceKind: ContainingTypeInstance) (OperationKind.InstanceReference, Type: R, IsImplicit) (Syntax: 'F1')
ExpressionBody:
null
",
OperationTreeVerifier.GetOperationTree(comp, constructorOperation));
controlFlowGraph = Microsoft.CodeAnalysis.FlowAnalysis.ControlFlowGraph.Create(constructorOperation);
ControlFlowGraphVerifier.VerifyGraph(comp,
@"Block[B0] - Entry
Statements (0)
Next (Regular) Block[B1]
Block[B1] - Block
Predecessors: [B0]
Statements (1)
IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'F2 = ref F1;')
Expression:
ISimpleAssignmentOperation (IsRef) (OperationKind.SimpleAssignment, Type: System.Int32) (Syntax: 'F2 = ref F1')
Left:
IFieldReferenceOperation: ref readonly System.Int32 R.F2 (OperationKind.FieldReference, Type: System.Int32) (Syntax: 'F2')
Instance Receiver:
IInstanceReferenceOperation (ReferenceKind: ContainingTypeInstance) (OperationKind.InstanceReference, Type: R, IsImplicit) (Syntax: 'F2')
Right:
IFieldReferenceOperation: ref System.Int32 R.F1 (OperationKind.FieldReference, Type: System.Int32) (Syntax: 'F1')
Instance Receiver:
IInstanceReferenceOperation (ReferenceKind: ContainingTypeInstance) (OperationKind.InstanceReference, Type: R, IsImplicit) (Syntax: 'F1')
Next (Regular) Block[B2]
Block[B2] - Exit
Predecessors: [B1]
Statements (0)
",
controlFlowGraph, symbol);
}
[Fact]
[WorkItem(63565, "https://github.com/dotnet/roslyn/issues/63565")]
public void UnscopedRefAttribute_DelegateConversion_01()
{
string source = """
using System.Diagnostics.CodeAnalysis;
ref struct R { }
class Program
{
static void Main()
{
var a = ([UnscopedRef] ref int x1, ref int y1) => ref y1;
var b = ([UnscopedRef] ref int x2, R y2) => y2;
var c = ([UnscopedRef] ref int x3, ref R y3) => { };
var d = ([UnscopedRef] out int x4) => { x4 = 0; return ref x4; };
var e = ([UnscopedRef] ref int x5) => x5;
var f = ([UnscopedRef] ref int x6) => ref x6;
var g = ref readonly int ([UnscopedRef] in int x7) => ref x7;
}
}
""";
var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70);
comp.VerifyEmitDiagnostics();
}
[Fact]
[WorkItem(63565, "https://github.com/dotnet/roslyn/issues/63565")]
public void UnscopedRefAttribute_DelegateConversion_02()
{
string source = """
using System.Diagnostics.CodeAnalysis;
ref struct R { }
class Program
{
static ref int F1(ref int y1, [UnscopedRef] ref int x1) => ref y1;
static R F2(R y2, [UnscopedRef] ref int x2) => y2;
static void F3(ref R y3, [UnscopedRef] ref int x3) { }
static ref int F4([UnscopedRef] out int x4) { x4 = 0; return ref x4; }
static int F5([UnscopedRef] ref int x5) => x5;
static ref int F6([UnscopedRef] ref int x6) => ref x6;
static ref readonly int F7([UnscopedRef] in int x7) => ref x7;
static void Main()
{
var a = F1;
var b = F2;
var c = F3;
var d = F4;
var e = F5;
var f = F6;
var g = F7;
}
}
""";
var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70);
comp.VerifyEmitDiagnostics();
}
[Fact]
[WorkItem(63565, "https://github.com/dotnet/roslyn/issues/63565")]
public void UnscopedRefAttribute_DelegateConversion_03()
{
string source = """
using System.Diagnostics.CodeAnalysis;
class Program
{
static ref int F1(ref int x, ref int y) => ref x;
static ref int F2(ref int x, [UnscopedRef] ref int y) => ref x;
static ref int F3([UnscopedRef] ref int x, [UnscopedRef] ref int y) => ref x;
static void Main()
{
var d1 = F1;
var d2 = F2;
var d3 = F3;
d1 = F2; // 1
d1 = F3; // 2, 3
d2 = F1;
d2 = F3; // 4
d3 = F1;
d2 = F2;
}
}
""";
var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70);
comp.VerifyEmitDiagnostics(
// (12,14): error CS8986: The 'scoped' modifier of parameter 'y' doesn't match target '<anonymous delegate>'.
// d1 = F2; // 1
Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "F2").WithArguments("y", "<anonymous delegate>").WithLocation(12, 14),
// (13,14): error CS8986: The 'scoped' modifier of parameter 'x' doesn't match target '<anonymous delegate>'.
// d1 = F3; // 2, 3
Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "F3").WithArguments("x", "<anonymous delegate>").WithLocation(13, 14),
// (13,14): error CS8986: The 'scoped' modifier of parameter 'y' doesn't match target '<anonymous delegate>'.
// d1 = F3; // 2, 3
Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "F3").WithArguments("y", "<anonymous delegate>").WithLocation(13, 14),
// (15,14): error CS8986: The 'scoped' modifier of parameter 'x' doesn't match target '<anonymous delegate>'.
// d2 = F3; // 4
Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "F3").WithArguments("x", "<anonymous delegate>").WithLocation(15, 14));
}
[Fact, WorkItem(64045, "https://github.com/dotnet/roslyn/issues/64045")]
public void ConstructorInvocationValEscape_01()
{
var source = """
class Program
{
static RS M1(scoped ref int i1) => new(ref i1);
static RS M2(scoped ref int i2)
{
return new(ref i2);
}
static RS M3(scoped ref int i3) => new RS(ref i3);
static RS M4(scoped ref int i4)
{
return new RS(ref i4);
}
}
ref struct RS
{
public RS(ref int i0) => throw null!;
}
""";
var comp = CreateCompilation(source);
comp.VerifyDiagnostics(
// (3,40): error CS8347: Cannot use a result of 'RS.RS(ref int)' in this context because it may expose variables referenced by parameter 'i0' outside of their declaration scope
// static RS M1(scoped ref int i1) => new(ref i1);
Diagnostic(ErrorCode.ERR_EscapeCall, "new(ref i1)").WithArguments("RS.RS(ref int)", "i0").WithLocation(3, 40),
// (3,48): error CS9075: Cannot return a parameter by reference 'i1' because it is scoped to the current method
// static RS M1(scoped ref int i1) => new(ref i1);
Diagnostic(ErrorCode.ERR_RefReturnScopedParameter, "i1").WithArguments("i1").WithLocation(3, 48),
// (6,16): error CS8347: Cannot use a result of 'RS.RS(ref int)' in this context because it may expose variables referenced by parameter 'i0' outside of their declaration scope
// return new(ref i2);
Diagnostic(ErrorCode.ERR_EscapeCall, "new(ref i2)").WithArguments("RS.RS(ref int)", "i0").WithLocation(6, 16),
// (6,24): error CS9075: Cannot return a parameter by reference 'i2' because it is scoped to the current method
// return new(ref i2);
Diagnostic(ErrorCode.ERR_RefReturnScopedParameter, "i2").WithArguments("i2").WithLocation(6, 24),
// (9,40): error CS8347: Cannot use a result of 'RS.RS(ref int)' in this context because it may expose variables referenced by parameter 'i0' outside of their declaration scope
// static RS M3(scoped ref int i3) => new RS(ref i3);
Diagnostic(ErrorCode.ERR_EscapeCall, "new RS(ref i3)").WithArguments("RS.RS(ref int)", "i0").WithLocation(9, 40),
// (9,51): error CS9075: Cannot return a parameter by reference 'i3' because it is scoped to the current method
// static RS M3(scoped ref int i3) => new RS(ref i3);
Diagnostic(ErrorCode.ERR_RefReturnScopedParameter, "i3").WithArguments("i3").WithLocation(9, 51),
// (12,16): error CS8347: Cannot use a result of 'RS.RS(ref int)' in this context because it may expose variables referenced by parameter 'i0' outside of their declaration scope
// return new RS(ref i4);
Diagnostic(ErrorCode.ERR_EscapeCall, "new RS(ref i4)").WithArguments("RS.RS(ref int)", "i0").WithLocation(12, 16),
// (12,27): error CS9075: Cannot return a parameter by reference 'i4' because it is scoped to the current method
// return new RS(ref i4);
Diagnostic(ErrorCode.ERR_RefReturnScopedParameter, "i4").WithArguments("i4").WithLocation(12, 27));
}
[Fact, WorkItem(64045, "https://github.com/dotnet/roslyn/issues/64045")]
public void ConstructorInvocationValEscape_02()
{
var source = """
class Program
{
static void M()
{
Del lam1 = (scoped ref int i1) => new(ref i1); // 1
Del lam2 = (scoped ref int i2) =>
{
return new(ref i2); // 2
};
Del lam3 = (scoped ref int i3) => new RS(ref i3); // 3
Del lam4 = (scoped ref int i4) =>
{
return new RS(ref i4); // 4
};
}
}
ref struct RS
{
public RS(ref int i0) => throw null!;
}
delegate RS Del(scoped ref int i);
""";
var comp = CreateCompilation(source);
comp.VerifyDiagnostics(
// (5,43): error CS8347: Cannot use a result of 'RS.RS(ref int)' in this context because it may expose variables referenced by parameter 'i0' outside of their declaration scope
// Del lam1 = (scoped ref int i1) => new(ref i1); // 1
Diagnostic(ErrorCode.ERR_EscapeCall, "new(ref i1)").WithArguments("RS.RS(ref int)", "i0").WithLocation(5, 43),
// (5,51): error CS9075: Cannot return a parameter by reference 'i1' because it is scoped to the current method
// Del lam1 = (scoped ref int i1) => new(ref i1); // 1
Diagnostic(ErrorCode.ERR_RefReturnScopedParameter, "i1").WithArguments("i1").WithLocation(5, 51),
// (8,20): error CS8347: Cannot use a result of 'RS.RS(ref int)' in this context because it may expose variables referenced by parameter 'i0' outside of their declaration scope
// return new(ref i2); // 2
Diagnostic(ErrorCode.ERR_EscapeCall, "new(ref i2)").WithArguments("RS.RS(ref int)", "i0").WithLocation(8, 20),
// (8,28): error CS9075: Cannot return a parameter by reference 'i2' because it is scoped to the current method
// return new(ref i2); // 2
Diagnostic(ErrorCode.ERR_RefReturnScopedParameter, "i2").WithArguments("i2").WithLocation(8, 28),
// (11,43): error CS8347: Cannot use a result of 'RS.RS(ref int)' in this context because it may expose variables referenced by parameter 'i0' outside of their declaration scope
// Del lam3 = (scoped ref int i3) => new RS(ref i3); // 3
Diagnostic(ErrorCode.ERR_EscapeCall, "new RS(ref i3)").WithArguments("RS.RS(ref int)", "i0").WithLocation(11, 43),
// (11,54): error CS9075: Cannot return a parameter by reference 'i3' because it is scoped to the current method
// Del lam3 = (scoped ref int i3) => new RS(ref i3); // 3
Diagnostic(ErrorCode.ERR_RefReturnScopedParameter, "i3").WithArguments("i3").WithLocation(11, 54),
// (14,20): error CS8347: Cannot use a result of 'RS.RS(ref int)' in this context because it may expose variables referenced by parameter 'i0' outside of their declaration scope
// return new RS(ref i4); // 4
Diagnostic(ErrorCode.ERR_EscapeCall, "new RS(ref i4)").WithArguments("RS.RS(ref int)", "i0").WithLocation(14, 20),
// (14,31): error CS9075: Cannot return a parameter by reference 'i4' because it is scoped to the current method
// return new RS(ref i4); // 4
Diagnostic(ErrorCode.ERR_RefReturnScopedParameter, "i4").WithArguments("i4").WithLocation(14, 31));
}
[Fact, WorkItem(65648, "https://github.com/dotnet/roslyn/issues/65648")]
public void ReturnRefToRefStruct_ValEscape_01()
{
var source = """
using System.Diagnostics.CodeAnalysis;
public class Repro
{
private static void Bad1(int value)
{
RefStruct s1 = new RefStruct();
s1.RefField = ref value; // 1
}
private static void Bad2(int value)
{
RefStruct s1 = new RefStruct();
s1.RefProperty.RefField = ref value; // 2
}
private static void Bad3(int value)
{
RefStruct s1 = new RefStruct();
s1.RefMethod().RefField = ref value; // 3
}
private ref struct RefStruct
{
public ref int RefField;
[UnscopedRef] public ref RefStruct RefProperty => ref this;
[UnscopedRef] public ref RefStruct RefMethod() => ref this;
}
}
""";
var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70);
comp.VerifyDiagnostics(
// (8,9): error CS8374: Cannot ref-assign 'value' to 'RefField' because 'value' has a narrower escape scope than 'RefField'.
// s1.RefField = ref value; // 1
Diagnostic(ErrorCode.ERR_RefAssignNarrower, "s1.RefField = ref value").WithArguments("RefField", "value").WithLocation(8, 9),
// (14,9): error CS8374: Cannot ref-assign 'value' to 'RefField' because 'value' has a narrower escape scope than 'RefField'.
// s1.RefProperty.RefField = ref value; // 2
Diagnostic(ErrorCode.ERR_RefAssignNarrower, "s1.RefProperty.RefField = ref value").WithArguments("RefField", "value").WithLocation(14, 9),
// (20,9): error CS8374: Cannot ref-assign 'value' to 'RefField' because 'value' has a narrower escape scope than 'RefField'.
// s1.RefMethod().RefField = ref value; // 3
Diagnostic(ErrorCode.ERR_RefAssignNarrower, "s1.RefMethod().RefField = ref value").WithArguments("RefField", "value").WithLocation(20, 9));
}
[Fact, WorkItem(65648, "https://github.com/dotnet/roslyn/issues/65648")]
public void ReturnRefToRefStruct_ValEscape_02()
{
var source = """
using System.Diagnostics.CodeAnalysis;
public class Repro
{
private static void Bad1(scoped ref RefStruct s1, int value)
{
s1.RefField = ref value; // 1
}
private static void Bad2(scoped ref RefStruct s1, int value)
{
s1.RefProperty.RefField = ref value; // 2
}
private static void Bad3(scoped ref RefStruct s1, int value)
{
s1.RefMethod().RefField = ref value; // 3
}
private static void Bad4(scoped in RefStruct s1, int value)
{
s1.RefField = ref value; // 4
}
private static void Bad5(scoped in RefStruct s1, int value)
{
s1.RefProperty.RefField = ref value; // 5
}
private static void Bad6(scoped in RefStruct s1, int value)
{
s1.RefMethod().RefField = ref value; // 6
}
private static void Bad7(in RefStruct s1, int value)
{
s1.RefField = ref value; // 7
}
private static void Bad8(in RefStruct s1, int value)
{
s1.RefProperty.RefField = ref value; // 8
}
private static void Bad9(in RefStruct s1, int value)
{
s1.RefMethod().RefField = ref value; // 9
}
private ref struct RefStruct
{
public ref int RefField;
[UnscopedRef] public ref RefStruct RefProperty => ref this;
[UnscopedRef] public ref RefStruct RefMethod() => ref this;
}
}
""";
// NB: 8 and 9 are not strictly necessary here because they are assigning to an implicit copy of a readonly variable, not to the original variable.
// However, it is not deeply problematic that an error is given here.
var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70);
comp.VerifyDiagnostics(
// (7,9): error CS8374: Cannot ref-assign 'value' to 'RefField' because 'value' has a narrower escape scope than 'RefField'.
// s1.RefField = ref value; // 1
Diagnostic(ErrorCode.ERR_RefAssignNarrower, "s1.RefField = ref value").WithArguments("RefField", "value").WithLocation(7, 9),
// (12,9): error CS8374: Cannot ref-assign 'value' to 'RefField' because 'value' has a narrower escape scope than 'RefField'.
// s1.RefProperty.RefField = ref value; // 2
Diagnostic(ErrorCode.ERR_RefAssignNarrower, "s1.RefProperty.RefField = ref value").WithArguments("RefField", "value").WithLocation(12, 9),
// (17,9): error CS8374: Cannot ref-assign 'value' to 'RefField' because 'value' has a narrower escape scope than 'RefField'.
// s1.RefMethod().RefField = ref value; // 3
Diagnostic(ErrorCode.ERR_RefAssignNarrower, "s1.RefMethod().RefField = ref value").WithArguments("RefField", "value").WithLocation(17, 9),
// (22,9): error CS8332: Cannot assign to a member of variable 's1' or use it as the right hand side of a ref assignment because it is a readonly variable
// s1.RefField = ref value; // 4
Diagnostic(ErrorCode.ERR_AssignReadonlyNotField2, "s1.RefField").WithArguments("variable", "s1").WithLocation(22, 9),
// (27,9): error CS8374: Cannot ref-assign 'value' to 'RefField' because 'value' has a narrower escape scope than 'RefField'.
// s1.RefProperty.RefField = ref value; // 5
Diagnostic(ErrorCode.ERR_RefAssignNarrower, "s1.RefProperty.RefField = ref value").WithArguments("RefField", "value").WithLocation(27, 9),
// (32,9): error CS8374: Cannot ref-assign 'value' to 'RefField' because 'value' has a narrower escape scope than 'RefField'.
// s1.RefMethod().RefField = ref value; // 6
Diagnostic(ErrorCode.ERR_RefAssignNarrower, "s1.RefMethod().RefField = ref value").WithArguments("RefField", "value").WithLocation(32, 9),
// (37,9): error CS8332: Cannot assign to a member of variable 's1' or use it as the right hand side of a ref assignment because it is a readonly variable
// s1.RefField = ref value; // 7
Diagnostic(ErrorCode.ERR_AssignReadonlyNotField2, "s1.RefField").WithArguments("variable", "s1").WithLocation(37, 9),
// (42,9): error CS8374: Cannot ref-assign 'value' to 'RefField' because 'value' has a narrower escape scope than 'RefField'.
// s1.RefProperty.RefField = ref value; // 8
Diagnostic(ErrorCode.ERR_RefAssignNarrower, "s1.RefProperty.RefField = ref value").WithArguments("RefField", "value").WithLocation(42, 9),
// (47,9): error CS8374: Cannot ref-assign 'value' to 'RefField' because 'value' has a narrower escape scope than 'RefField'.
// s1.RefMethod().RefField = ref value; // 9
Diagnostic(ErrorCode.ERR_RefAssignNarrower, "s1.RefMethod().RefField = ref value").WithArguments("RefField", "value").WithLocation(47, 9));
}
[Fact, WorkItem(65648, "https://github.com/dotnet/roslyn/issues/65648")]
public void ReturnRefToRefStruct_ValEscape_03()
{
var source = """
using System.Diagnostics.CodeAnalysis;
public class Repro
{
private static void Bad1(ref RefStruct s1, int value)
{
s1 = new RefStruct(ref value); // 1
}
private static void Bad2(scoped ref RefStruct s1, int value)
{
s1.RefProperty = new RefStruct(ref value); // 2
}
private static void Bad3(scoped ref RefStruct s1, int value)
{
s1.RefMethod() = new RefStruct(ref value); // 3
}
private static void Bad4(scoped ref RefStruct s1, int value)
{
GetRef(ref s1) = new RefStruct(ref value); // 4
}
private static ref RefStruct GetRef(ref RefStruct s) => ref s;
private ref struct RefStruct
{
public RefStruct(ref int i) => RefField = ref i;
public ref int RefField;
[UnscopedRef] public ref RefStruct RefProperty => ref this;
[UnscopedRef] public ref RefStruct RefMethod() => ref this;
}
}
""";
var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70);
comp.VerifyDiagnostics(
// (7,14): error CS8347: Cannot use a result of 'Repro.RefStruct.RefStruct(ref int)' in this context because it may expose variables referenced by parameter 'i' outside of their declaration scope
// s1 = new RefStruct(ref value); // 1
Diagnostic(ErrorCode.ERR_EscapeCall, "new RefStruct(ref value)").WithArguments("Repro.RefStruct.RefStruct(ref int)", "i").WithLocation(7, 14),
// (7,32): error CS8166: Cannot return a parameter by reference 'value' because it is not a ref parameter
// s1 = new RefStruct(ref value); // 1
Diagnostic(ErrorCode.ERR_RefReturnParameter, "value").WithArguments("value").WithLocation(7, 32),
// (12,26): error CS8347: Cannot use a result of 'Repro.RefStruct.RefStruct(ref int)' in this context because it may expose variables referenced by parameter 'i' outside of their declaration scope
// s1.RefProperty = new RefStruct(ref value); // 2
Diagnostic(ErrorCode.ERR_EscapeCall, "new RefStruct(ref value)").WithArguments("Repro.RefStruct.RefStruct(ref int)", "i").WithLocation(12, 26),
// (12,44): error CS8166: Cannot return a parameter by reference 'value' because it is not a ref parameter
// s1.RefProperty = new RefStruct(ref value); // 2
Diagnostic(ErrorCode.ERR_RefReturnParameter, "value").WithArguments("value").WithLocation(12, 44),
// (17,26): error CS8347: Cannot use a result of 'Repro.RefStruct.RefStruct(ref int)' in this context because it may expose variables referenced by parameter 'i' outside of their declaration scope
// s1.RefMethod() = new RefStruct(ref value); // 3
Diagnostic(ErrorCode.ERR_EscapeCall, "new RefStruct(ref value)").WithArguments("Repro.RefStruct.RefStruct(ref int)", "i").WithLocation(17, 26),
// (17,44): error CS8166: Cannot return a parameter by reference 'value' because it is not a ref parameter
// s1.RefMethod() = new RefStruct(ref value); // 3
Diagnostic(ErrorCode.ERR_RefReturnParameter, "value").WithArguments("value").WithLocation(17, 44),
// (22,26): error CS8347: Cannot use a result of 'Repro.RefStruct.RefStruct(ref int)' in this context because it may expose variables referenced by parameter 'i' outside of their declaration scope
// GetRef(ref s1) = new RefStruct(ref value); // 4
Diagnostic(ErrorCode.ERR_EscapeCall, "new RefStruct(ref value)").WithArguments("Repro.RefStruct.RefStruct(ref int)", "i").WithLocation(22, 26),
// (22,44): error CS8166: Cannot return a parameter by reference 'value' because it is not a ref parameter
// GetRef(ref s1) = new RefStruct(ref value); // 4
Diagnostic(ErrorCode.ERR_RefReturnParameter, "value").WithArguments("value").WithLocation(22, 44));
}
[Fact, WorkItem(65648, "https://github.com/dotnet/roslyn/issues/65648")]
public void ReturnRefToRefStruct_ValEscape_04()
{
// test that the appropriate filtering of escape-values is occurring when the RTRS expression is on the RHS of an an assignment.
var source = """
using System.Diagnostics.CodeAnalysis;
public class Repro
{
private static void M1(ref RefStruct s1, int value)
{
// 's2' only contributes STE, not RSTE, to the STE of 'RefMethod()' invocation.
// STE is equal to RSTE for 's2', so it doesn't matter.
var s2 = new RefStruct(ref value);
s1 = s2.RefMethod(); // 1
}
private static void M2(ref RefStruct s1, ref RefStruct s2)
{
// 's2' only contributes STE, not RSTE, to the STE of 'RefMethod()' invocation.
// RSTE of `s2` is narrower than STE of 's1', but STE of 's2' equals STE of 's1', so we expect no error here.
s1 = s2.RefMethod();
}
private ref struct RefStruct
{
public RefStruct(ref int i) => RefField = ref i;
public ref int RefField;
[UnscopedRef] public ref RefStruct RefMethod() => ref this;
}
}
""";
var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70);
comp.VerifyDiagnostics(
// (10,14): error CS8352: Cannot use variable 's2' in this context because it may expose referenced variables outside of their declaration scope
// s1 = s2.RefMethod(); // 1
Diagnostic(ErrorCode.ERR_EscapeVariable, "s2").WithArguments("s2").WithLocation(10, 14));
}
[Fact, WorkItem(65648, "https://github.com/dotnet/roslyn/issues/65648")]
public void ReturnRefToRefStruct_RefEscape_01()
{
var source = """
public class Repro
{
private static ref RefStruct M1(ref RefStruct s1, ref RefStruct s2)
{
bool b = false;
return ref b ? ref s1 : ref s2;
}
private static ref RefStruct M2(ref RefStruct s1)
{
RefStruct s2 = default;
// RSTE of s1 is ReturnOnly
// RSTE of s2 is CurrentMethod
return ref M1(ref s1, ref s2); // 1
}
private static ref RefStruct M3(ref RefStruct s1)
{
return ref M1(ref s1, ref s1);
}
private ref struct RefStruct { }
}
""";
var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70);
comp.VerifyDiagnostics(
// (14,20): error CS8347: Cannot use a result of 'Repro.M1(ref Repro.RefStruct, ref Repro.RefStruct)' in this context because it may expose variables referenced by parameter 's2' outside of their declaration scope
// return ref M1(ref s1, ref s2); // 1
Diagnostic(ErrorCode.ERR_EscapeCall, "M1(ref s1, ref s2)").WithArguments("Repro.M1(ref Repro.RefStruct, ref Repro.RefStruct)", "s2").WithLocation(14, 20),
// (14,35): error CS8168: Cannot return local 's2' by reference because it is not a ref local
// return ref M1(ref s1, ref s2); // 1
Diagnostic(ErrorCode.ERR_RefReturnLocal, "s2").WithArguments("s2").WithLocation(14, 35)
);
}
[Fact, WorkItem(65648, "https://github.com/dotnet/roslyn/issues/65648")]
public void ReturnRefToRefStruct_RefEscape_BothScopedAndUnscopedRefParameters()
{
var source = """
public class Repro
{
private static ref RefStruct M1(ref RefStruct s1, scoped ref RefStruct s2)
{
return ref s1;
}
private static ref RefStruct M2(ref RefStruct s1)
{
RefStruct s2 = default;
// RSTE of s1 is ReturnOnly
// RSTE of s2 is CurrentMethod, but it doesn't contribute to RSTE of the invocation.
return ref M1(ref s1, ref s2);
}
private static ref RefStruct M3(ref RefStruct s1)
{
return ref M1(ref s1, ref s1);
}
private ref struct RefStruct { }
}
""";
var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70);
comp.VerifyDiagnostics();
}
[Fact, WorkItem(65648, "https://github.com/dotnet/roslyn/issues/65648")]
public void ReturnRefToRefStruct_RefEscape_02()
{
var source = """
public class Repro
{
private static ref RefStruct M1(ref RefStruct s1, RefStruct s2)
{
return ref s1;
}
private static ref RefStruct M2(ref RefStruct s1, int param)
{
RefStruct s2 = new RefStruct(ref param);
// RSTE of s1 is ReturnOnly
// STE of s2 is CurrentMethod, but this is not contributed to the call to M1.
// We error due to arg mixing, not due to the return value.
return ref M1(ref s1, s2);
}
private ref struct RefStruct
{
public RefStruct(ref int i) { }
}
}
""";
var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70);
comp.VerifyDiagnostics(
// (14,20): error CS8350: This combination of arguments to 'Repro.M1(ref Repro.RefStruct, Repro.RefStruct)' is disallowed because it may expose variables referenced by parameter 's2' outside of their declaration scope
// return ref M1(ref s1, s2);
Diagnostic(ErrorCode.ERR_CallArgMixing, "M1(ref s1, s2)").WithArguments("Repro.M1(ref Repro.RefStruct, Repro.RefStruct)", "s2").WithLocation(14, 20),
// (14,31): error CS8352: Cannot use variable 's2' in this context because it may expose referenced variables outside of their declaration scope
// return ref M1(ref s1, s2);
Diagnostic(ErrorCode.ERR_EscapeVariable, "s2").WithArguments("s2").WithLocation(14, 31)
);
}
[Fact, WorkItem(65648, "https://github.com/dotnet/roslyn/issues/65648")]
public void ReturnRefToRefStruct_VariousInputAndOutputRefKinds()
{
var source = """
using System.Diagnostics.CodeAnalysis;
public class Repro
{
private static void Bad1(int value)
{
RefStruct s1 = new RefStruct();
GetReference1(ref s1).RefField = ref value; // 1
GetReference2(in s1).RefField = ref value; // 2
GetReference3(out s1).RefField = ref value; // 3
GetReadonlyReference1(ref s1).RefField = ref value; // 4
GetReadonlyReference2(in s1).RefField = ref value; // 5
GetReadonlyReference3(out s1).RefField = ref value; // 6
}
static ref RefStruct GetReference1(ref RefStruct rs) => throw null!;
static ref RefStruct GetReference2(in RefStruct rs) => throw null!;
static ref RefStruct GetReference3([UnscopedRef] out RefStruct rs) => throw null!;
static ref readonly RefStruct GetReadonlyReference1(ref RefStruct rs) => throw null!;
static ref readonly RefStruct GetReadonlyReference2(in RefStruct rs) => throw null!;
static ref readonly RefStruct GetReadonlyReference3([UnscopedRef] out RefStruct rs) => throw null!;
private ref struct RefStruct
{
public ref int RefField;
}
}
""";
var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70);
comp.VerifyDiagnostics(
// (8,9): error CS8374: Cannot ref-assign 'value' to 'RefField' because 'value' has a narrower escape scope than 'RefField'.
// GetReference1(ref s1).RefField = ref value; // 1
Diagnostic(ErrorCode.ERR_RefAssignNarrower, "GetReference1(ref s1).RefField = ref value").WithArguments("RefField", "value").WithLocation(8, 9),
// (9,9): error CS8374: Cannot ref-assign 'value' to 'RefField' because 'value' has a narrower escape scope than 'RefField'.
// GetReference2(in s1).RefField = ref value; // 2
Diagnostic(ErrorCode.ERR_RefAssignNarrower, "GetReference2(in s1).RefField = ref value").WithArguments("RefField", "value").WithLocation(9, 9),
// (10,9): error CS8374: Cannot ref-assign 'value' to 'RefField' because 'value' has a narrower escape scope than 'RefField'.
// GetReference3(out s1).RefField = ref value; // 3
Diagnostic(ErrorCode.ERR_RefAssignNarrower, "GetReference3(out s1).RefField = ref value").WithArguments("RefField", "value").WithLocation(10, 9),
// (12,9): error CS8332: Cannot assign to a member of method 'GetReadonlyReference1' or use it as the right hand side of a ref assignment because it is a readonly variable
// GetReadonlyReference1(ref s1).RefField = ref value; // 4
Diagnostic(ErrorCode.ERR_AssignReadonlyNotField2, "GetReadonlyReference1(ref s1).RefField").WithArguments("method", "GetReadonlyReference1").WithLocation(12, 9),
// (13,9): error CS8332: Cannot assign to a member of method 'GetReadonlyReference2' or use it as the right hand side of a ref assignment because it is a readonly variable
// GetReadonlyReference2(in s1).RefField = ref value; // 5
Diagnostic(ErrorCode.ERR_AssignReadonlyNotField2, "GetReadonlyReference2(in s1).RefField").WithArguments("method", "GetReadonlyReference2").WithLocation(13, 9),
// (14,9): error CS8332: Cannot assign to a member of method 'GetReadonlyReference3' or use it as the right hand side of a ref assignment because it is a readonly variable
// GetReadonlyReference3(out s1).RefField = ref value; // 6
Diagnostic(ErrorCode.ERR_AssignReadonlyNotField2, "GetReadonlyReference3(out s1).RefField").WithArguments("method", "GetReadonlyReference3").WithLocation(14, 9));
}
[WorkItem(66128, "https://github.com/dotnet/roslyn/issues/66128")]
[ConditionalFact(typeof(CoreClrOnly))]
public void DefensiveCopy_RefReadOnlyReceiver_01()
{
var source = """
using System;
class Program
{
static void Main()
{
S s = new();
ref readonly S r = ref s;
M(in r);
Console.WriteLine(r);
}
static void M(in S s)
{
R r = new(in s);
r.S.M();
}
}
struct S
{
int i;
public void M() { i++; }
public readonly override string ToString() => i.ToString();
}
ref struct R
{
public ref readonly S S;
public R(in S s) { S = ref s; }
}
""";
var verifier = CompileAndVerify(source, targetFramework: TargetFramework.Net70, expectedOutput: "0");
verifier.VerifyIL("Program.M", """
{
// Code size 27 (0x1b)
.maxstack 1
.locals init (R V_0, //r
S V_1)
IL_0000: ldarg.0
IL_0001: newobj "R..ctor(in S)"
IL_0006: stloc.0
IL_0007: ldloc.0
IL_0008: ldfld "ref readonly S R.S"
IL_000d: ldobj "S"
IL_0012: stloc.1
IL_0013: ldloca.s V_1
IL_0015: call "void S.M()"
IL_001a: ret
}
""");
}
[WorkItem(66128, "https://github.com/dotnet/roslyn/issues/66128")]
[ConditionalFact(typeof(CoreClrOnly))]
public void DefensiveCopy_RefReadOnlyReceiver_02()
{
var source = """
using System;
class Program
{
static void Main()
{
R r = new R(new S());
Console.WriteLine(r.S);
}
}
struct S
{
int i;
public void M1() { i++; }
public readonly void M2() { }
public readonly override string ToString() => i.ToString();
}
ref struct R
{
public ref readonly S S;
public R(in S s)
{
S = ref s;
S.M1();
}
public R(in S s, object o)
{
S = ref s;
S.M2();
}
}
""";
var verifier = CompileAndVerify(source, targetFramework: TargetFramework.Net70, expectedOutput: "0");
verifier.VerifyIL("R..ctor(in S)", """
{
// Code size 27 (0x1b)
.maxstack 2
.locals init (S V_0)
IL_0000: ldarg.0
IL_0001: ldarg.1
IL_0002: stfld "ref readonly S R.S"
IL_0007: ldarg.0
IL_0008: ldfld "ref readonly S R.S"
IL_000d: ldobj "S"
IL_0012: stloc.0
IL_0013: ldloca.s V_0
IL_0015: call "void S.M1()"
IL_001a: ret
}
""");
verifier.VerifyIL("R..ctor(in S, object)", """
{
// Code size 19 (0x13)
.maxstack 2
IL_0000: ldarg.0
IL_0001: ldarg.1
IL_0002: stfld "ref readonly S R.S"
IL_0007: ldarg.0
IL_0008: ldfld "ref readonly S R.S"
IL_000d: call "readonly void S.M2()"
IL_0012: ret
}
""");
}
[WorkItem(66128, "https://github.com/dotnet/roslyn/issues/66128")]
[ConditionalFact(typeof(CoreClrOnly))]
public void DefensiveCopy_RefReadOnlyReceiver_03()
{
var source = """
using System;
class Program
{
static void Main()
{
R r1 = new R(new S()) { P1 = 1 };
Console.WriteLine(r1.S);
R r2 = new R(new S()) { P2 = 2 };
Console.WriteLine(r2.S);
}
}
struct S
{
int i;
public void M() { i++; }
public readonly override string ToString() => i.ToString();
}
ref struct R
{
public ref readonly S S;
public R(in S s)
{
S = ref s;
}
public object P1
{
get { return null; }
set { S.M(); }
}
public object P2
{
get { return null; }
init { S.M(); }
}
}
""";
var verifier = CompileAndVerify(source, targetFramework: TargetFramework.Net70, expectedOutput: """
0
0
""");
string expectedIL = """
{
// Code size 20 (0x14)
.maxstack 1
.locals init (S V_0)
IL_0000: ldarg.0
IL_0001: ldfld "ref readonly S R.S"
IL_0006: ldobj "S"
IL_000b: stloc.0
IL_000c: ldloca.s V_0
IL_000e: call "void S.M()"
IL_0013: ret
}
""";
verifier.VerifyIL("R.P1.set", expectedIL);
verifier.VerifyIL("R.P2.init", expectedIL);
}
[Theory]
[InlineData(LanguageVersion.CSharp10)]
[InlineData(LanguageVersion.CSharp11)]
public void ConstructorInitializer_01(LanguageVersion languageVersion)
{
var source = """
using System;
class A
{
public A(ref Span<int> x, Span<int> y) { }
A(ref Span<int> s) : this(ref s, new Span<int>()) { }
A(ref Span<int> s, int i) : this(ref s, stackalloc int[1]) { } // 1
}
class B : A
{
B(ref Span<int> s) : base(ref s, new Span<int>()) { }
B(ref Span<int> s, int i) : base(ref s, stackalloc int[2]) { } // 2
}
""";
var comp = CreateCompilationWithSpan(source, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion));
comp.VerifyDiagnostics(
// (6,31): error CS8350: This combination of arguments to 'A.A(ref Span<int>, Span<int>)' is disallowed because it may expose variables referenced by parameter 'y' outside of their declaration scope
// A(ref Span<int> s, int i) : this(ref s, stackalloc int[1]) { } // 1
Diagnostic(ErrorCode.ERR_CallArgMixing, ": this(ref s, stackalloc int[1])").WithArguments("A.A(ref System.Span<int>, System.Span<int>)", "y").WithLocation(6, 31),
// (6,45): 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
// A(ref Span<int> s, int i) : this(ref s, stackalloc int[1]) { } // 1
Diagnostic(ErrorCode.ERR_EscapeStackAlloc, "stackalloc int[1]").WithArguments("System.Span<int>").WithLocation(6, 45),
// (11,31): error CS8350: This combination of arguments to 'A.A(ref Span<int>, Span<int>)' is disallowed because it may expose variables referenced by parameter 'y' outside of their declaration scope
// B(ref Span<int> s, int i) : base(ref s, stackalloc int[2]) { } // 2
Diagnostic(ErrorCode.ERR_CallArgMixing, ": base(ref s, stackalloc int[2])").WithArguments("A.A(ref System.Span<int>, System.Span<int>)", "y").WithLocation(11, 31),
// (11,45): 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
// B(ref Span<int> s, int i) : base(ref s, stackalloc int[2]) { } // 2
Diagnostic(ErrorCode.ERR_EscapeStackAlloc, "stackalloc int[2]").WithArguments("System.Span<int>").WithLocation(11, 45));
}
[Fact]
public void ConstructorInitializer_02()
{
var source = """
ref struct R
{
R(in int i) { }
R(int x, int y) : this(x) { } // 1
}
""";
var comp = CreateCompilation(source);
comp.VerifyDiagnostics(
// (4,21): error CS8350: This combination of arguments to 'R.R(in int)' is disallowed because it may expose variables referenced by parameter 'i' outside of their declaration scope
// R(int x, int y) : this(x) { } // 1
Diagnostic(ErrorCode.ERR_CallArgMixing, ": this(x)").WithArguments("R.R(in int)", "i").WithLocation(4, 21),
// (4,28): error CS8166: Cannot return a parameter by reference 'x' because it is not a ref parameter
// R(int x, int y) : this(x) { } // 1
Diagnostic(ErrorCode.ERR_RefReturnParameter, "x").WithArguments("x").WithLocation(4, 28));
}
[Theory]
[InlineData(LanguageVersion.CSharp10)]
[InlineData(LanguageVersion.CSharp11)]
public void FunctionPointerInvocation_01(LanguageVersion languageVersion)
{
var source = """
using System;
class Program
{
static void F0(ref Span<int> x, Span<int> y)
{
}
static unsafe void F1(ref Span<int> s)
{
delegate*<ref Span<int>, Span<int>, void> f = &F0;
f(ref s, new Span<int>());
f(ref s, stackalloc int[1]); // 1
}
}
""";
var comp = CreateCompilationWithSpan(source, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion), options: TestOptions.UnsafeReleaseDll);
comp.VerifyDiagnostics(
// (11,18): warning CS9081: A result of a stackalloc expression of type 'Span<int>' in this context may be exposed outside of the containing method
// f(ref s, stackalloc int[1]); // 1
Diagnostic(ErrorCode.WRN_EscapeStackAlloc, "stackalloc int[1]").WithArguments("System.Span<int>").WithLocation(11, 18));
}
[Fact]
public void FunctionPointerInvocation_02()
{
var source = """
ref struct R
{
}
class Program
{
static void F0(out R r, in int i)
{
r = default;
}
static unsafe void F1(out R r1, in int i1)
{
delegate*<out R, in int, void> f = &F0;
f(out r1, i1);
}
static unsafe void F2(out R r1, int i2)
{
delegate*<out R, in int, void> f = &F0;
f(out r1, i2); // 1
}
}
""";
var comp = CreateCompilationWithSpan(source, options: TestOptions.UnsafeReleaseDll);
comp.VerifyDiagnostics(
// (18,19): warning CS9087: This returns a parameter by reference 'i2' but it is not a ref parameter
// f(out r1, i2); // 1
Diagnostic(ErrorCode.WRN_RefReturnParameter, "i2").WithArguments("i2").WithLocation(18, 19));
}
[Fact]
public void PatternIndex_01()
{
string source = """
using System;
using System.Diagnostics.CodeAnalysis;
ref struct R
{
public int Length => 0;
[UnscopedRef] public ref int this[int i] => throw null;
}
class Program
{
static ref int F1(ref R r1)
{
ref int i1 = ref r1[^1];
return ref i1;
}
static ref int F2(ref R r2, Index i)
{
ref int i2 = ref r2[i];
return ref i2;
}
static ref int F3()
{
R r3 = new R();
ref int i3 = ref r3[^3];
return ref i3; // 1
}
static ref int F4(Index i)
{
R r4 = new R();
ref int i4 = ref r4[i];
return ref i4; // 2
}
}
""";
var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70);
comp.VerifyDiagnostics(
// (24,20): error CS8157: Cannot return 'i3' by reference because it was initialized to a value that cannot be returned by reference
// return ref i3; // 1
Diagnostic(ErrorCode.ERR_RefReturnNonreturnableLocal, "i3").WithArguments("i3").WithLocation(24, 20),
// (30,20): error CS8157: Cannot return 'i4' by reference because it was initialized to a value that cannot be returned by reference
// return ref i4; // 2
Diagnostic(ErrorCode.ERR_RefReturnNonreturnableLocal, "i4").WithArguments("i4").WithLocation(30, 20));
}
[Fact]
public void PatternIndex_02()
{
string source = """
ref struct R
{
public R(ref int i) { }
public int Length => 0;
public R this[int i] => throw null;
}
class Program
{
static R F1()
{
R r1 = new R();
if (r1 is [.., var r]) return r;
return r1;
}
static R F2()
{
int i2 = 2;
R r2 = new R(ref i2);
if (r2 is [.., var r]) return r; // 1
return r2; // 2
}
}
""";
var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70);
comp.VerifyDiagnostics(
// (19,39): error CS8352: Cannot use variable 'r' in this context because it may expose referenced variables outside of their declaration scope
// if (r2 is [.., var r]) return r; // 1
Diagnostic(ErrorCode.ERR_EscapeVariable, "r").WithArguments("r").WithLocation(19, 39),
// (20,16): error CS8352: Cannot use variable 'r2' in this context because it may expose referenced variables outside of their declaration scope
// return r2; // 2
Diagnostic(ErrorCode.ERR_EscapeVariable, "r2").WithArguments("r2").WithLocation(20, 16));
}
[Fact]
public void PatternIndex_03()
{
string source = """
ref struct R
{
public R(ref int i) { }
public int Length => 0;
public int this[int i] => 0;
public R Slice(int x, int y) => this;
}
class Program
{
static R F1()
{
R r1 = new R();
if (r1 is [.. [> 0] r]) return r;
return r1;
}
static R F2()
{
int i2 = 2;
R r2 = new R(ref i2);
if (r2 is [.. [> 0] r]) return r; // 1
return r2; // 2
}
}
""";
var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70);
comp.VerifyDiagnostics(
// (20,40): error CS8352: Cannot use variable 'r' in this context because it may expose referenced variables outside of their declaration scope
// if (r2 is [.. [> 0] r]) return r; // 1
Diagnostic(ErrorCode.ERR_EscapeVariable, "r").WithArguments("r").WithLocation(20, 40),
// (21,16): error CS8352: Cannot use variable 'r2' in this context because it may expose referenced variables outside of their declaration scope
// return r2; // 2
Diagnostic(ErrorCode.ERR_EscapeVariable, "r2").WithArguments("r2").WithLocation(21, 16));
}
[Fact]
public void TopLevelStatementLocal()
{
var source = """
int i = 0;
ref int r = ref i;
class C
{
static void F1() { F2(ref r); }
static ref int F2(ref int r) => ref r;
}
""";
var comp = CreateCompilation(source);
comp.VerifyDiagnostics(
// (5,31): error CS8801: Cannot use local variable or local function 'r' declared in a top-level statement in this context.
// static void F1() { F2(ref r); }
Diagnostic(ErrorCode.ERR_SimpleProgramLocalIsReferencedOutsideOfTopLevelStatement, "r").WithArguments("r").WithLocation(5, 31),
// (5,31): error CS0165: Use of unassigned local variable 'r'
// static void F1() { F2(ref r); }
Diagnostic(ErrorCode.ERR_UseDefViolation, "r").WithArguments("r").WithLocation(5, 31));
}
[Fact]
public void Discard_01()
{
var source = """
class Program
{
static ref int F1()
{
return ref F2(out _);
}
static ref int F2(out int i)
{
i = 0;
return ref i;
}
}
""";
var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10);
comp.VerifyDiagnostics(
// (5,20): error CS8347: Cannot use a result of 'Program.F2(out int)' in this context because it may expose variables referenced by parameter 'i' outside of their declaration scope
// return ref F2(out _);
Diagnostic(ErrorCode.ERR_EscapeCall, "F2(out _)").WithArguments("Program.F2(out int)", "i").WithLocation(5, 20),
// (5,27): error CS8156: An expression cannot be used in this context because it may not be passed or returned by reference
// return ref F2(out _);
Diagnostic(ErrorCode.ERR_RefReturnLvalueExpected, "_").WithLocation(5, 27));
}
[Fact]
public void Discard_02()
{
var source = """
using System.Diagnostics.CodeAnalysis;
class Program
{
static ref int F1()
{
return ref F2(out _);
}
static ref int F2([UnscopedRef] out int i)
{
i = 0;
return ref i;
}
}
""";
var comp = CreateCompilation(new[] { source, UnscopedRefAttributeDefinition });
comp.VerifyDiagnostics(
// (6,20): error CS8347: Cannot use a result of 'Program.F2(out int)' in this context because it may expose variables referenced by parameter 'i' outside of their declaration scope
// return ref F2(out _);
Diagnostic(ErrorCode.ERR_EscapeCall, "F2(out _)").WithArguments("Program.F2(out int)", "i").WithLocation(6, 20),
// (6,27): error CS8156: An expression cannot be used in this context because it may not be passed or returned by reference
// return ref F2(out _);
Diagnostic(ErrorCode.ERR_RefReturnLvalueExpected, "_").WithLocation(6, 27));
}
[Theory]
[InlineData(LanguageVersion.CSharp10)]
[InlineData(LanguageVersion.CSharp11)]
public void Discard_03(LanguageVersion languageVersion)
{
var source = """
ref struct R
{
public void Deconstruct(out int x, out R y)
{
x = 0;
y = default;
}
}
class Program
{
static R F1()
{
R r1 = default;
int i;
(i, _) = r1;
return r1;
}
static R F2()
{
R r2 = default;
int i;
r2.Deconstruct(out i, out _);
return r2;
}
}
""";
var comp = CreateCompilation(source, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion));
comp.VerifyDiagnostics();
}
[Fact]
public void SwitchExpression_Assignment()
{
var source = """
using System;
class Program
{
static void M()
{
Span<int> s;
Span<int> outer = stackalloc int[100];
s = outer switch
{
Span<int> inner => inner
};
}
}
""";
var comp = CreateCompilationWithSpan(source);
comp.VerifyDiagnostics(
// (10,32): error CS8352: Cannot use variable 'inner' in this context because it may expose referenced variables outside of their declaration scope
// Span<int> inner => inner
Diagnostic(ErrorCode.ERR_EscapeVariable, "inner").WithArguments("inner").WithLocation(10, 32));
}
[Fact]
public void SwitchExpression_Argument()
{
var source = """
using System;
class Program
{
static Span<int> F(Span<int> x, Span<int> y)
{
return x;
}
static void M()
{
Span<int> x = default;
Span<int> y = stackalloc int[100];
x = F(x, y switch { Span<int> inner => inner });
}
}
""";
var comp = CreateCompilationWithSpan(source);
comp.VerifyDiagnostics(
// (12,13): error CS8347: Cannot use a result of 'Program.F(Span<int>, Span<int>)' in this context because it may expose variables referenced by parameter 'y' outside of their declaration scope
// x = F(x, y switch { Span<int> inner => inner });
Diagnostic(ErrorCode.ERR_EscapeCall, "F(x, y switch { Span<int> inner => inner })").WithArguments("Program.F(System.Span<int>, System.Span<int>)", "y").WithLocation(12, 13),
// (12,48): error CS8352: Cannot use variable 'inner' in this context because it may expose referenced variables outside of their declaration scope
// x = F(x, y switch { Span<int> inner => inner });
Diagnostic(ErrorCode.ERR_EscapeVariable, "inner").WithArguments("inner").WithLocation(12, 48));
}
[Fact]
public void SwitchExpression_Return()
{
var source = """
using System;
class Program
{
static Span<int> M()
{
Span<int> outer = stackalloc int[100];
return outer switch
{
Span<int> inner => inner
};
}
}
""";
var comp = CreateCompilationWithSpan(source);
comp.VerifyDiagnostics(
// (9,32): error CS8352: Cannot use variable 'inner' in this context because it may expose referenced variables outside of their declaration scope
// Span<int> inner => inner
Diagnostic(ErrorCode.ERR_EscapeVariable, "inner").WithArguments("inner").WithLocation(9, 32));
}
[Fact]
public void SwitchExpression_YieldReturn()
{
var source = """
using System;
using System.Collections.Generic;
class Program
{
static IEnumerable<int> M()
{
Span<int> outer = stackalloc int[100];
yield return (outer switch
{
Span<int> inner => inner
})[0];
}
}
""";
var comp = CreateCompilationWithSpan(source);
comp.VerifyDiagnostics();
}
[Fact]
public void SwitchExpression_FieldInitializer()
{
var source = """
using System;
class Program
{
static int F = (new Span<int>() switch
{
Span<int> inner => inner
})[0];
}
""";
var comp = CreateCompilationWithSpan(source);
comp.VerifyDiagnostics();
}
[Fact]
public void UnsafeContext_LocalFunction_01()
{
var source = """
#pragma warning disable 8321
class Program
{
static ref int F0(ref int x, ref int y)
{
return ref x;
}
static void F1()
{
static ref int Local1(ref int x1, int y1)
{
return ref F0(ref x1, ref y1);
}
unsafe static ref int Local2(ref int x2, int y2)
{
return ref F0(ref x2, ref y2);
}
unsafe
{
static ref int Local3(ref int x3, int y3)
{
return ref F0(ref x3, ref y3);
}
unsafe static ref int Local4(ref int x4, int y4)
{
return ref F0(ref x4, ref y4);
}
}
}
}
""";
var comp = CreateCompilation(source, options: TestOptions.UnsafeReleaseDll);
comp.VerifyDiagnostics(
// (12,24): error CS8347: Cannot use a result of 'Program.F0(ref int, ref int)' in this context because it may expose variables referenced by parameter 'y' outside of their declaration scope
// return ref F0(ref x1, ref y1);
Diagnostic(ErrorCode.ERR_EscapeCall, "F0(ref x1, ref y1)").WithArguments("Program.F0(ref int, ref int)", "y").WithLocation(12, 24),
// (12,39): error CS8166: Cannot return a parameter by reference 'y1' because it is not a ref parameter
// return ref F0(ref x1, ref y1);
Diagnostic(ErrorCode.ERR_RefReturnParameter, "y1").WithArguments("y1").WithLocation(12, 39),
// (16,39): warning CS9087: This returns a parameter by reference 'y2' but it is not a ref parameter
// return ref F0(ref x2, ref y2);
Diagnostic(ErrorCode.WRN_RefReturnParameter, "y2").WithArguments("y2").WithLocation(16, 39),
// (22,43): warning CS9087: This returns a parameter by reference 'y3' but it is not a ref parameter
// return ref F0(ref x3, ref y3);
Diagnostic(ErrorCode.WRN_RefReturnParameter, "y3").WithArguments("y3").WithLocation(22, 43),
// (26,43): warning CS9087: This returns a parameter by reference 'y4' but it is not a ref parameter
// return ref F0(ref x4, ref y4);
Diagnostic(ErrorCode.WRN_RefReturnParameter, "y4").WithArguments("y4").WithLocation(26, 43));
}
[Fact]
public void UnsafeContext_LocalFunction_02()
{
var source = """
#pragma warning disable 8321
class A
{
internal static ref int F0(ref int x, ref int y)
{
return ref x;
}
}
class B1 : A
{
unsafe static void F1()
{
static ref int Local1(ref int x1, int y1)
{
return ref F0(ref x1, ref y1);
}
}
unsafe class B2 : A
{
static void F2()
{
static ref int Local2(ref int x2, int y2)
{
return ref F0(ref x2, ref y2);
}
}
}
""";
var comp = CreateCompilation(source, options: TestOptions.UnsafeReleaseDll);
comp.VerifyDiagnostics(
// (15,39): warning CS9087: This returns a parameter by reference 'y1' but it is not a ref parameter
// return ref F0(ref x1, ref y1);
Diagnostic(ErrorCode.WRN_RefReturnParameter, "y1").WithArguments("y1").WithLocation(15, 39),
// (24,39): warning CS9087: This returns a parameter by reference 'y2' but it is not a ref parameter
// return ref F0(ref x2, ref y2);
Diagnostic(ErrorCode.WRN_RefReturnParameter, "y2").WithArguments("y2").WithLocation(24, 39),
// (27,2): error CS1513: } expected
// }
Diagnostic(ErrorCode.ERR_RbraceExpected, "").WithLocation(27, 2));
}
}
}
|