/
githubmirror
/
roslyn
Обзор
Документация
Войти
/
githubmirror
/
roslyn
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
src/Compilers/CSharp/Test/Semantic/Semantics/RefFieldTests.cs
32 351 строка
1 MB
Jan Jones
Unsafe evolution: make pointers safe regardless of memory safety rules version (#83133)
21 апр 2026, 11:27
Не верифицирован
21 апр 2026, 11:27
fca0128
Код
Авторство
О чём код?
// 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 { [CompilerTrait(CompilerFeature.RefLifetime)] public class RefFieldTests : CSharpTestBase { internal 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.Mscorlib461); 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); } [WorkItem(78700, "https://github.com/dotnet/roslyn/issues/78700")] [Fact] public void StaticRefFieldInClass() { var code = """ class Program { static int g_3 = -6; static int g_4 = 123; static ref int g_2 = ref g_3; static void Main(){ g_2 = ref g_4; } } """; var comp = CreateCompilation(code, references: [], parseOptions: TestOptions.Regular13, targetFramework: TargetFramework.Net70); comp.VerifyEmitDiagnostics( // (5,20): error CS0106: The modifier 'static' is not valid for this item // static ref int g_2 = ref g_3; Diagnostic(ErrorCode.ERR_BadMemberFlag, "g_2").WithArguments("static").WithLocation(5, 20), // (5,20): error CS9059: A ref field can only be declared in a ref struct. // static ref int g_2 = ref g_3; Diagnostic(ErrorCode.ERR_RefFieldInNonRefStruct, "g_2").WithLocation(5, 20)); } [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, parseOptions: TestOptions.Regular14); 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) ); var expectedPreviewDiagnostics = new[] { // (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,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) }; comp = CreateCompilation(source, options: TestOptions.UnsafeReleaseDll, targetFramework: TargetFramework.Net70); comp.VerifyEmitDiagnostics(expectedPreviewDiagnostics); comp = CreateCompilation(source, options: TestOptions.UnsafeReleaseDll, targetFramework: TargetFramework.Net70, parseOptions: TestOptions.RegularNext); comp.VerifyEmitDiagnostics(expectedPreviewDiagnostics); } [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, parseOptions: TestOptions.Regular14); 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) ); var expectedPreviewDiagnostics = new[] { // (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), // (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), // (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) }; comp = CreateCompilation(source, options: TestOptions.UnsafeReleaseDll, targetFramework: TargetFramework.Net70); comp.VerifyEmitDiagnostics(expectedPreviewDiagnostics); comp = CreateCompilation(source, options: TestOptions.UnsafeReleaseDll, targetFramework: TargetFramework.Net70, parseOptions: TestOptions.RegularNext); comp.VerifyEmitDiagnostics(expectedPreviewDiagnostics); } [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, parseOptions: TestOptions.Regular14); 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) ); var expectedPreviewDiagnostics = new[] { // (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), // (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) }; comp = CreateCompilation(source, options: TestOptions.UnsafeReleaseDll, targetFramework: TargetFramework.Net70); comp.VerifyEmitDiagnostics(expectedPreviewDiagnostics); comp = CreateCompilation(source, options: TestOptions.UnsafeReleaseDll, targetFramework: TargetFramework.Net70, parseOptions: TestOptions.RegularNext); comp.VerifyEmitDiagnostics(expectedPreviewDiagnostics); 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(TestSources.Span, 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(TestSources.Span, 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(TestSources.Span, 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(TestSources.Span, 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 CS9265: Field 'R.field' is never ref-assigned to, and will always have its default value (null reference) // public readonly ref int field; Diagnostic(ErrorCode.WRN_UnassignedInternalRefField, "field").WithArguments("R.field").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)); } [Theory] [InlineData("class")] [InlineData("struct")] [InlineData("record")] [InlineData("record struct")] public void NonRefStructContainerWithStaticRefField(string type) { var source = $@"#pragma warning disable 169 {type} R {{ static ref int F; }}"; var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10, targetFramework: TargetFramework.Net70); comp.VerifyEmitDiagnostics( // (4,12): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater. // static ref int F; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "ref int").WithArguments("ref fields", "11.0").WithLocation(4, 12), // (4,20): error CS0106: The modifier 'static' is not valid for this item // static ref int F; Diagnostic(ErrorCode.ERR_BadMemberFlag, "F").WithArguments("static").WithLocation(4, 20), // (4,20): error CS9059: A ref field can only be declared in a ref struct. // static ref int F; Diagnostic(ErrorCode.ERR_RefFieldInNonRefStruct, "F").WithLocation(4, 20)); comp = CreateCompilation(source, targetFramework: TargetFramework.Net70); comp.VerifyEmitDiagnostics( // (4,20): error CS0106: The modifier 'static' is not valid for this item // static ref int F; Diagnostic(ErrorCode.ERR_BadMemberFlag, "F").WithArguments("static").WithLocation(4, 20), // (4,20): error CS9059: A ref field can only be declared in a ref struct. // static ref int F; Diagnostic(ErrorCode.ERR_RefFieldInNonRefStruct, "F").WithLocation(4, 20)); } /// <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 9265 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 = CreateCompilationWithMscorlib461(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 = CreateCompilationWithMscorlib461(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 = CreateCompilationWithMscorlib461(source, parseOptions: TestOptions.Regular10); comp.VerifyEmitDiagnostics(); comp = CreateCompilationWithMscorlib461(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( // (3,19): warning CS9265: Field 'R<T>._t' is never ref-assigned to, and will always have its default value (null reference) // private ref T _t; Diagnostic(ErrorCode.WRN_UnassignedInternalRefField, "_t").WithArguments("R<T>._t").WithLocation(3, 19), // (4,25): warning CS9201: Ref field '_t' should be ref-assigned before use. // public R(ref T t) { _t = t; } Diagnostic(ErrorCode.WRN_UseDefViolationRefField, "_t").WithArguments("_t").WithLocation(4, 25)); } [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,19): error CS8352: Cannot use variable '[x] = 1' 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] = 1 }").WithArguments("[x] = 1").WithLocation(13, 19), // (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() { 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( // (3,18): warning CS9265: Field 'S<T>.F' is never ref-assigned to, and will always have its default value (null reference) // public ref T F; Diagnostic(ErrorCode.WRN_UnassignedInternalRefField, "F").WithArguments("S<T>.F").WithLocation(3, 18), // (6,9): warning CS9201: Ref field 'F' should be ref-assigned before use. // F = t; Diagnostic(ErrorCode.WRN_UseDefViolationRefField, "F").WithArguments("F").WithLocation(6, 9)); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/75315")] public void DefiniteAssignment_WarningWave() { var source = """ ref struct R { public ref int F; } """; CreateCompilation(source, options: TestOptions.ReleaseDll.WithWarningLevel(9), targetFramework: TargetFramework.Net70).VerifyDiagnostics(); var expectedDiagnostics = new[] { // (3,20): warning CS9265: Field 'R.F' is never ref-assigned to, and will always have its default value (null reference) // public ref int F; Diagnostic(ErrorCode.WRN_UnassignedInternalRefField, "F").WithArguments("R.F").WithLocation(3, 20) }; CreateCompilation(source, options: TestOptions.ReleaseDll.WithWarningLevel(10), targetFramework: TargetFramework.Net70).VerifyDiagnostics(expectedDiagnostics); CreateCompilation(source, targetFramework: TargetFramework.Net70).VerifyDiagnostics(expectedDiagnostics); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/75315")] public void DefiniteAssignment_RefField_Unassigned_InAtCallSite() { var comp = CreateCompilation(""" ref struct R { public ref int F; static void M(in int x) { } static void Test(R r) { M(in r.F); } } """, targetFramework: TargetFramework.NetCoreApp); comp.VerifyDiagnostics( // (3,20): warning CS9265: Field 'R.F' is never ref-assigned to, and will always have its default value (null reference) // public ref int F; Diagnostic(ErrorCode.WRN_UnassignedInternalRefField, "F").WithArguments("R.F").WithLocation(3, 20)); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/75315")] public void DefiniteAssignment_RefField_RefAssigned_InAtCallSite() { var comp = CreateCompilation(""" ref struct R { public ref int F; static void M(in int x) { } static void Test(scoped R r, ref int x) { r.F = ref x; M(in r.F); } } """, targetFramework: TargetFramework.NetCoreApp); comp.VerifyDiagnostics(); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/75315")] public void DefiniteAssignment_RefField_RefAssignedInObjectInitializer_InAtCallSite() { var comp = CreateCompilation(""" ref struct R { public ref int F; static void M(in int x) { } static void Test(ref int x) { var r = new R { F = ref x }; M(in r.F); } } """, targetFramework: TargetFramework.NetCoreApp); comp.VerifyDiagnostics(); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/75315")] public void DefiniteAssignment_RefField_Assigned_InAtCallSite() { var comp = CreateCompilation(""" ref struct R { public ref int F; static void M(in int x) { } static void Test(R r, int x) { r.F = x; M(in r.F); } } """, targetFramework: TargetFramework.NetCoreApp); comp.VerifyDiagnostics( // (3,20): warning CS9265: Field 'R.F' is never ref-assigned to, and will always have its default value (null reference) // public ref int F; Diagnostic(ErrorCode.WRN_UnassignedInternalRefField, "F").WithArguments("R.F").WithLocation(3, 20)); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/75315")] public void DefiniteAssignment_RefField_Assigned_Nested() { var comp = CreateCompilation(""" ref struct R1 { public ref R2 F; } ref struct R2 { public ref int F; } class C { static void Test(R1 r, int x) { r.F.F = x; } } """, targetFramework: TargetFramework.NetCoreApp); comp.VerifyDiagnostics( // (3,12): error CS9050: A ref field cannot refer to a ref struct. // public ref R2 F; Diagnostic(ErrorCode.ERR_RefFieldCannotReferToRefStruct, "ref R2").WithLocation(3, 12), // (3,19): warning CS9265: Field 'R1.F' is never ref-assigned to, and will always have its default value (null reference) // public ref R2 F; Diagnostic(ErrorCode.WRN_UnassignedInternalRefField, "F").WithArguments("R1.F").WithLocation(3, 19), // (8,20): warning CS9265: Field 'R2.F' is never ref-assigned to, and will always have its default value (null reference) // public ref int F; Diagnostic(ErrorCode.WRN_UnassignedInternalRefField, "F").WithArguments("R2.F").WithLocation(8, 20)); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/75315")] public void DefiniteAssignment_RefField_RefAssigned_Nested() { var comp = CreateCompilation(""" ref struct R1 { public ref R2 F; } ref struct R2 { public ref int F; } class C { static void Test(scoped R1 r, ref int x) { r.F.F = ref x; } } """, targetFramework: TargetFramework.NetCoreApp); comp.VerifyDiagnostics( // (3,12): error CS9050: A ref field cannot refer to a ref struct. // public ref R2 F; Diagnostic(ErrorCode.ERR_RefFieldCannotReferToRefStruct, "ref R2").WithLocation(3, 12), // (3,19): warning CS9265: Field 'R1.F' is never ref-assigned to, and will always have its default value (null reference) // public ref R2 F; Diagnostic(ErrorCode.WRN_UnassignedInternalRefField, "F").WithArguments("R1.F").WithLocation(3, 19)); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/75315")] public void DefiniteAssignment_RefField_AssignedInObjectInitializer_InAtCallSite() { var comp = CreateCompilation(""" ref struct R { public ref int F; static void M(in int x) { } static void Test(int x) { var r = new R { F = x }; M(in r.F); } } """, targetFramework: TargetFramework.NetCoreApp); comp.VerifyDiagnostics( // (3,20): warning CS9265: Field 'R.F' is never ref-assigned to, and will always have its default value (null reference) // public ref int F; Diagnostic(ErrorCode.WRN_UnassignedInternalRefField, "F").WithArguments("R.F").WithLocation(3, 20)); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/75315")] public void DefiniteAssignment_ValueField_Unassigned_InAtCallSite() { var comp = CreateCompilation(""" ref struct R { public int F; static void M(in int x) { } static void Test(R r) { M(in r.F); } } """, targetFramework: TargetFramework.NetCoreApp); comp.VerifyDiagnostics( // (3,16): warning CS0649: Field 'R.F' is never assigned to, and will always have its default value 0 // public int F; Diagnostic(ErrorCode.WRN_UnassignedInternalField, "F").WithArguments("R.F", "0").WithLocation(3, 16)); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/75315")] public void DefiniteAssignment_RefField_Unassigned_PlainAtCallSite() { var comp = CreateCompilation(""" ref struct R { public ref int F; static void M(in int x) { } static void Test(R r) { M(r.F); } } """, targetFramework: TargetFramework.NetCoreApp); comp.VerifyDiagnostics( // (3,20): warning CS9265: Field 'R.F' is never ref-assigned to, and will always have its default value (null reference) // public ref int F; Diagnostic(ErrorCode.WRN_UnassignedInternalRefField, "F").WithArguments("R.F").WithLocation(3, 20)); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/75315")] public void DefiniteAssignment_ValueField_Unassigned_PlainAtCallSite() { var comp = CreateCompilation(""" ref struct R { public int F; static void M(in int x) { } static void Test(R r) { M(r.F); } } """, targetFramework: TargetFramework.NetCoreApp); comp.VerifyDiagnostics( // (3,16): warning CS0649: Field 'R.F' is never assigned to, and will always have its default value 0 // public int F; Diagnostic(ErrorCode.WRN_UnassignedInternalField, "F").WithArguments("R.F", "0").WithLocation(3, 16)); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/75315")] public void DefiniteAssignment_RefField_Unassigned_RefAtCallSite() { var comp = CreateCompilation(""" ref struct R { public ref int F; static void M(ref int x) { } static void Test(R r) { M(ref r.F); } } """, targetFramework: TargetFramework.NetCoreApp); comp.VerifyDiagnostics( // (3,20): warning CS9265: Field 'R.F' is never ref-assigned to, and will always have its default value (null reference) // public ref int F; Diagnostic(ErrorCode.WRN_UnassignedInternalRefField, "F").WithArguments("R.F").WithLocation(3, 20)); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/75315")] public void DefiniteAssignment_ValueField_Unassigned_RefAtCallSite() { var comp = CreateCompilation(""" ref struct R { public int F; static void M(ref int x) { } static void Test(R r) { M(ref r.F); } } """, targetFramework: TargetFramework.NetCoreApp); comp.VerifyDiagnostics(); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/75315")] public void DefiniteAssignment_RefField_Unassigned_OutAtCallSite() { var comp = CreateCompilation(""" ref struct R { public ref int F; static void M(out int x) => throw null; static void Test(R r) { M(out r.F); } } """, targetFramework: TargetFramework.NetCoreApp); comp.VerifyDiagnostics( // (3,20): warning CS9265: Field 'R.F' is never ref-assigned to, and will always have its default value (null reference) // public ref int F; Diagnostic(ErrorCode.WRN_UnassignedInternalRefField, "F").WithArguments("R.F").WithLocation(3, 20)); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/75315")] public void DefiniteAssignment_ValueField_Unassigned_OutAtCallSite() { var comp = CreateCompilation(""" ref struct R { public int F; static void M(out int x) => throw null; static void Test(R r) { M(out r.F); } } """, targetFramework: TargetFramework.NetCoreApp); comp.VerifyDiagnostics(); } [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( // 0.cs(3,18): warning CS9265: Field 'S<T>.F' is never ref-assigned to, and will always have its default value (null reference) // public ref T F; Diagnostic(ErrorCode.WRN_UnassignedInternalRefField, "F").WithArguments("S<T>.F").WithLocation(3, 18), // 0.cs(7,9): warning CS9201: Ref field 'F' should be ref-assigned before use. // F = tValue; Diagnostic(ErrorCode.WRN_UseDefViolationRefField, "F").WithArguments("F").WithLocation(7, 9)); } [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( // (3,27): warning CS9265: Field 'S<T>.F' is never ref-assigned to, and will always have its default value (null reference) // public ref readonly T F; Diagnostic(ErrorCode.WRN_UnassignedInternalRefField, "F").WithArguments("S<T>.F").WithLocation(3, 27), // (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), // (7,9): warning CS9201: Ref field 'F' should be ref-assigned before use. // F = tValue; // 1 Diagnostic(ErrorCode.WRN_UseDefViolationRefField, "F").WithArguments("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( // 0.cs(3,27): warning CS9265: Field 'S<T>.F' is never ref-assigned to, and will always have its default value (null reference) // public readonly ref T F; Diagnostic(ErrorCode.WRN_UnassignedInternalRefField, "F").WithArguments("S<T>.F").WithLocation(3, 27), // 0.cs(7,9): warning CS9201: Ref field 'F' should be ref-assigned before use. // F = tValue; Diagnostic(ErrorCode.WRN_UseDefViolationRefField, "F").WithArguments("F").WithLocation(7, 9)); } [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( // (3,36): warning CS9265: Field 'S<T>.F' is never ref-assigned to, and will always have its default value (null reference) // public readonly ref readonly T F; Diagnostic(ErrorCode.WRN_UnassignedInternalRefField, "F").WithArguments("S<T>.F").WithLocation(3, 36), // (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), // (7,9): warning CS9201: Ref field 'F' should be ref-assigned before use. // F = tValue; // 1 Diagnostic(ErrorCode.WRN_UseDefViolationRefField, "F").WithArguments("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 9265 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( // (3,18): warning CS9265: Field 'S<T>.Ref' is never ref-assigned to, and will always have its default value (null reference) // public ref T Ref; Diagnostic(ErrorCode.WRN_UnassignedInternalRefField, "Ref").WithArguments("S<T>.Ref").WithLocation(3, 18), // (4,27): warning CS9265: Field 'S<T>.RefReadonly' is never ref-assigned to, and will always have its default value (null reference) // public ref readonly T RefReadonly; Diagnostic(ErrorCode.WRN_UnassignedInternalRefField, "RefReadonly").WithArguments("S<T>.RefReadonly").WithLocation(4, 27), // (5,27): warning CS9265: Field 'S<T>.ReadonlyRef' is never ref-assigned to, and will always have its default value (null reference) // public readonly ref T ReadonlyRef; Diagnostic(ErrorCode.WRN_UnassignedInternalRefField, "ReadonlyRef").WithArguments("S<T>.ReadonlyRef").WithLocation(5, 27), // (6,36): warning CS9265: Field 'S<T>.ReadonlyRefReadonly' is never ref-assigned to, and will always have its default value (null reference) // public readonly ref readonly T ReadonlyRefReadonly; Diagnostic(ErrorCode.WRN_UnassignedInternalRefField, "ReadonlyRefReadonly").WithArguments("S<T>.ReadonlyRefReadonly").WithLocation(6, 36), // (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( // (3,18): warning CS9265: Field 'S<T>.Ref' is never ref-assigned to, and will always have its default value (null reference) // public ref T Ref; Diagnostic(ErrorCode.WRN_UnassignedInternalRefField, "Ref").WithArguments("S<T>.Ref").WithLocation(3, 18), // (4,27): warning CS9265: Field 'S<T>.RefReadonly' is never ref-assigned to, and will always have its default value (null reference) // public ref readonly T RefReadonly; Diagnostic(ErrorCode.WRN_UnassignedInternalRefField, "RefReadonly").WithArguments("S<T>.RefReadonly").WithLocation(4, 27), // (5,27): warning CS9265: Field 'S<T>.ReadonlyRef' is never ref-assigned to, and will always have its default value (null reference) // public readonly ref T ReadonlyRef; Diagnostic(ErrorCode.WRN_UnassignedInternalRefField, "ReadonlyRef").WithArguments("S<T>.ReadonlyRef").WithLocation(5, 27), // (6,36): warning CS9265: Field 'S<T>.ReadonlyRefReadonly' is never ref-assigned to, and will always have its default value (null reference) // public readonly ref readonly T ReadonlyRefReadonly; Diagnostic(ErrorCode.WRN_UnassignedInternalRefField, "ReadonlyRefReadonly").WithArguments("S<T>.ReadonlyRefReadonly").WithLocation(6, 36)); } [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( // (3,18): warning CS9265: Field 'S<T>.F' is never ref-assigned to, and will always have its default value (null reference) // public ref T F; Diagnostic(ErrorCode.WRN_UnassignedInternalRefField, "F").WithArguments("S<T>.F").WithLocation(3, 18)); } [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( // (3,27): warning CS9265: Field 'S<T>.F' is never ref-assigned to, and will always have its default value (null reference) // public ref readonly T F; Diagnostic(ErrorCode.WRN_UnassignedInternalRefField, "F").WithArguments("S<T>.F").WithLocation(3, 27), // (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( // (3,27): warning CS9265: Field 'S<T>.F' is never ref-assigned to, and will always have its default value (null reference) // public readonly ref T F; Diagnostic(ErrorCode.WRN_UnassignedInternalRefField, "F").WithArguments("S<T>.F").WithLocation(3, 27)); } [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( // (3,36): warning CS9265: Field 'S<T>.F' is never ref-assigned to, and will always have its default value (null reference) // public readonly ref readonly T F; Diagnostic(ErrorCode.WRN_UnassignedInternalRefField, "F").WithArguments("S<T>.F").WithLocation(3, 36), // (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( // (3,18): warning CS9265: Field 'S<T>.F' is never ref-assigned to, and will always have its default value (null reference) // public ref T F; Diagnostic(ErrorCode.WRN_UnassignedInternalRefField, "F").WithArguments("S<T>.F").WithLocation(3, 18)); } [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( // (3,27): warning CS9265: Field 'S<T>.F' is never ref-assigned to, and will always have its default value (null reference) // public ref readonly T F; Diagnostic(ErrorCode.WRN_UnassignedInternalRefField, "F").WithArguments("S<T>.F").WithLocation(3, 27), // (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( // (3,27): warning CS9265: Field 'S<T>.F' is never ref-assigned to, and will always have its default value (null reference) // public readonly ref T F; Diagnostic(ErrorCode.WRN_UnassignedInternalRefField, "F").WithArguments("S<T>.F").WithLocation(3, 27)); } [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( // (3,36): warning CS9265: Field 'S<T>.F' is never ref-assigned to, and will always have its default value (null reference) // public readonly ref readonly T F; Diagnostic(ErrorCode.WRN_UnassignedInternalRefField, "F").WithArguments("S<T>.F").WithLocation(3, 36), // (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 9265 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(Feature.PEVerifyCompat), 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 CS9244: The type 'Span<int>' may not be a ref struct or a type parameter allowing ref structs in order to use it as parameter 'T1' in the generic type or method '(T1, T2)' // (x, y) = (y, x); Diagnostic(ErrorCode.ERR_NotRefStructConstraintNotSatisfied, "y").WithArguments("(T1, T2)", "T1", "System.Span<int>").WithLocation(8, 19), // (8,22): error CS9244: The type 'Span<int>' may not be a ref struct or a type parameter allowing ref structs in order to use it as parameter 'T2' in the generic type or method '(T1, T2)' // (x, y) = (y, x); Diagnostic(ErrorCode.ERR_NotRefStructConstraintNotSatisfied, "x").WithArguments("(T1, T2)", "T2", "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): warning CS9269: UnscopedRefAttribute is only valid in C# 11 or later or when targeting net7.0 or later. // static ref S<T> F1<T>([UnscopedRef] ref S<T> x1) Diagnostic(ErrorCode.WRN_UnscopedRefAttributeOldRules, "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( // (14,26): error CS8350: This combination of arguments to 'Program.F1<T>(ref S<T>)' is disallowed because it may expose variables referenced by parameter 'x1' outside of their declaration scope // ref var y2 = ref F1(ref x2); Diagnostic(ErrorCode.ERR_CallArgMixing, "F1(ref x2)").WithArguments("Program.F1<T>(ref S<T>)", "x1").WithLocation(14, 26), // (14,33): error CS8166: Cannot return a parameter by reference 'x2' because it is not a ref parameter // ref var y2 = ref F1(ref x2); Diagnostic(ErrorCode.ERR_RefReturnParameter, "x2").WithArguments("x2").WithLocation(14, 33), // (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), // (28,21): warning CS9265: Field 'R.n' is never ref-assigned to, and will always have its default value (null reference) // private ref int n; Diagnostic(ErrorCode.WRN_UnassignedInternalRefField, "n").WithArguments("R.n").WithLocation(28, 21) ); } [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 CS9244: The type 'StructWithRefField' may not be a ref struct or a type parameter allowing ref structs in order to use it as parameter 'T' in the generic type or method 'C.M<T>()' // C.M<StructWithRefField>(); // 3 Diagnostic(ErrorCode.ERR_NotRefStructConstraintNotSatisfied, "M<StructWithRefField>").WithArguments("C.M<T>()", "T", "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 CS9244: The type 'StructWithIndirectRefField' may not be a ref struct or a type parameter allowing ref structs in order to use it as parameter 'T' in the generic type or method 'C.M<T>()' // C.M<StructWithIndirectRefField>(); // 3 Diagnostic(ErrorCode.ERR_NotRefStructConstraintNotSatisfied, "M<StructWithIndirectRefField>").WithArguments("C.M<T>()", "T", "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 CS9265: Field 'StructWithRefField<T>.RefField' is never ref-assigned to, and will always have its default value (null reference) // public ref T RefField; Diagnostic(ErrorCode.WRN_UnassignedInternalRefField, "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 escape 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 escape 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 escape 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 escape 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 escape 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 escape 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 escape 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 escape 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 escape 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): warning CS9269: UnscopedRefAttribute is only valid in C# 11 or later or when targeting net7.0 or later. // var f4 = (out int x4, scoped out int y4, [System.Diagnostics.CodeAnalysis.UnscopedRefAttribute] out int z4) => { x4 = 0; y4 = 0; z4 = 0; }; Diagnostic(ErrorCode.WRN_UnscopedRefAttributeOldRules, "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, false); verifyParameter(delegateTypesAndLambdas[0], 1, "scoped R", "y1", RefKind.None, ScopedKind.ScopedValue, false, false); verifyParameter(delegateTypesAndLambdas[1], 0, "ref System.Int32", "x2", RefKind.Ref, ScopedKind.None, false, false); verifyParameter(delegateTypesAndLambdas[1], 1, "scoped ref System.Int32", "y2", RefKind.Ref, ScopedKind.ScopedRef, false, false); verifyParameter(delegateTypesAndLambdas[2], 0, "in System.Int32", "x3", RefKind.In, ScopedKind.None, false, false); verifyParameter(delegateTypesAndLambdas[2], 1, "scoped in System.Int32", "y3", RefKind.In, ScopedKind.ScopedRef, false, false); verifyParameter(delegateTypesAndLambdas[3], 0, "out System.Int32", "x4", RefKind.Out, useUpdatedEscapeRules ? ScopedKind.ScopedRef : ScopedKind.None, false, false); verifyParameter(delegateTypesAndLambdas[3], 1, "out System.Int32", "y4", RefKind.Out, ScopedKind.ScopedRef, false, false); verifyParameter(delegateTypesAndLambdas[3], 2, "out System.Int32", "z4", RefKind.Out, ScopedKind.None, true, useUpdatedEscapeRules); verifyParameter(delegateTypesAndLambdas[4], 0, "ref R", "x5", RefKind.Ref, ScopedKind.None, false, false); verifyParameter(delegateTypesAndLambdas[4], 1, "scoped ref R", "y5", RefKind.Ref, ScopedKind.ScopedRef, false, false); verifyParameter(delegateTypesAndLambdas[5], 0, "in R", "x6", RefKind.In, ScopedKind.None, false, false); verifyParameter(delegateTypesAndLambdas[5], 1, "scoped in R", "y6", RefKind.In, ScopedKind.ScopedRef, false, false); verifyParameter(delegateTypesAndLambdas[6], 0, "out R", "x7", RefKind.Out, useUpdatedEscapeRules ? ScopedKind.ScopedRef : ScopedKind.None, false, false); verifyParameter(delegateTypesAndLambdas[6], 1, "out R", "y7", RefKind.Out, ScopedKind.ScopedRef, false, false); } static void verifyParameter((NamedTypeSymbol, LambdaSymbol) delegateTypeAndLambda, int parameterIndex, string expectedDisplayType, string expectedDisplayName, RefKind expectedRefKind, ScopedKind expectedScope, bool expectedHasUnscopedRefAttribute, bool expectedHasUnscopedRefAttributeInDelegate) { var (delegateType, lambda) = delegateTypeAndLambda; VerifyParameterSymbol(delegateType.DelegateInvokeMethod.Parameters[parameterIndex], $"{expectedDisplayType} arg{parameterIndex + 1}", expectedRefKind, expectedScope, expectedHasUnscopedRefAttributeInDelegate); 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_CSharp13() { 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, parseOptions: TestOptions.Regular13); comp.VerifyEmitDiagnostics( // (6,26): error CS1107: A parameter can only have one 'scoped' modifier // var f1 = (scoped scoped R r) => { }; Diagnostic(ErrorCode.ERR_DupParamMod, "scoped").WithArguments("scoped").WithLocation(6, 26), // (7,23): error CS9347: The 'scoped' modifier cannot come after an 'in', 'out', 'ref' or 'readonly' modifier. // var f2 = (ref scoped scoped R r) => { }; Diagnostic(ErrorCode.ERR_ScopedAfterInOutRefReadonly, "scoped").WithLocation(7, 23), // (7,30): error CS1107: A parameter can only have one 'scoped' modifier // var f2 = (ref scoped scoped R r) => { }; Diagnostic(ErrorCode.ERR_DupParamMod, "scoped").WithArguments("scoped").WithLocation(7, 30), // (8,19): error CS0246: The type or namespace name 'scoped' could not be found (are you missing a using directive or an assembly reference?) // var f3 = (scoped scoped ref R r) => { }; Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "scoped").WithArguments("scoped").WithLocation(8, 19), // (8,33): error CS1003: Syntax error, ',' expected // var f3 = (scoped scoped ref R r) => { }; Diagnostic(ErrorCode.ERR_SyntaxError, "ref").WithArguments(",").WithLocation(8, 33)); } [Fact] public void ParameterScope_08_CSharp14() { 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, parseOptions: TestOptions.Regular14); comp.VerifyEmitDiagnostics( // (6,26): error CS1107: A parameter can only have one 'scoped' modifier // var f1 = (scoped scoped R r) => { }; Diagnostic(ErrorCode.ERR_DupParamMod, "scoped").WithArguments("scoped").WithLocation(6, 26), // (7,23): error CS9347: The 'scoped' modifier cannot come after an 'in', 'out', 'ref' or 'readonly' modifier. // var f2 = (ref scoped scoped R r) => { }; Diagnostic(ErrorCode.ERR_ScopedAfterInOutRefReadonly, "scoped").WithLocation(7, 23), // (7,30): error CS1107: A parameter can only have one 'scoped' modifier // var f2 = (ref scoped scoped R r) => { }; Diagnostic(ErrorCode.ERR_DupParamMod, "scoped").WithArguments("scoped").WithLocation(7, 30), // (8,26): error CS1107: A parameter can only have one 'scoped' modifier // var f3 = (scoped scoped ref R r) => { }; Diagnostic(ErrorCode.ERR_DupParamMod, "scoped").WithArguments("scoped").WithLocation(8, 26)); } [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,30): error CS9348: The 'this' modifier cannot immediately follow the 'scoped' modifier. // static void F2<T>(scoped this R<T> r) { } Diagnostic(ErrorCode.ERR_InvalidModifierAfterScoped, "this").WithArguments("this").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 R<T> r", RefKind.None, ScopedKind.ScopedValue); 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], "params scoped 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,1): error CS0116: A namespace cannot directly contain members such as fields, methods or statements // scoped readonly ref struct C { } Diagnostic(ErrorCode.ERR_NamespaceUnexpected, "scoped").WithLocation(3, 1)); } [Fact] public void TypeScopeModifier_02_CSharp10() { var source = @"scoped record A { } scoped readonly record struct B; readonly scoped record struct C(); "; var comp = CreateCompilation(source, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp10)); 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 CS9348: A compilation unit cannot directly contain members such as fields, methods or properties // scoped record A { } Diagnostic(ErrorCode.ERR_CompilationUnitUnexpected, "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,1): error CS0116: A namespace cannot directly contain members such as fields, methods or statements // scoped readonly record struct B; Diagnostic(ErrorCode.ERR_NamespaceUnexpected, "scoped").WithLocation(2, 1), // (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 CS8936: Feature 'primary constructors' is not available in C# 10.0. Please use language version 12.0 or greater. // readonly scoped record struct C(); Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "()").WithArguments("primary constructors", "12.0").WithLocation(3, 32)); } [Fact] public void TypeScopeModifier_02_CSharp11() { var source = @"scoped record A { } scoped readonly record struct B; readonly scoped record struct C(); "; var comp = CreateCompilation(source, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp11)); 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 CS9348: A compilation unit cannot directly contain members such as fields, methods or properties // scoped record A { } Diagnostic(ErrorCode.ERR_CompilationUnitUnexpected, "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,1): error CS0116: A namespace cannot directly contain members such as fields, methods or statements // scoped readonly record struct B; Diagnostic(ErrorCode.ERR_NamespaceUnexpected, "scoped").WithLocation(2, 1), // (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 CS9058: Feature 'primary constructors' is not available in C# 11.0. Please use language version 12.0 or greater. // readonly scoped record struct C(); Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion11, "()").WithArguments("primary constructors", "12.0").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.Mscorlib461); 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(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(Feature.RunNullableAnalysis, "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(Feature.RunNullableAnalysis, "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(Feature.RunNullableAnalysis, "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(Feature.RunNullableAnalysis, "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(Feature.RunNullableAnalysis, "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,20): error CS1593: Delegate 'D1' does not take 0 arguments // D1 d1 = () => new R(); Diagnostic(ErrorCode.ERR_BadDelArgCount, "=>").WithArguments("D1", "0").WithLocation(12, 20)); } [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,19): error CS1593: Delegate 'D1' does not take 1 arguments // D1 d1 = r => r; Diagnostic(ErrorCode.ERR_BadDelArgCount, "=>").WithArguments("D1", "1").WithLocation(12, 19), // (13,30): error CS1593: Delegate 'D1' does not take 1 arguments // D1 d2 = (scoped R r) => r; Diagnostic(ErrorCode.ERR_BadDelArgCount, "=>").WithArguments("D1", "1").WithLocation(13, 30)); } [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 definition. // 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 definition. // 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 definition. // 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 definition. // 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 definition. // 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 definition. // 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 definition. // 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 definition. // 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 definition. // 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 definition. // 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, [CombinatorialValues("in", "ref readonly")] string modifier) { 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(" + modifier + @" T t); public abstract ref T F6(scoped " + modifier + @" 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(" + modifier + @" int i) => throw null; public override ref int F6(scoped " + modifier + @" 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 " + modifier + @" string s) => throw null; public override ref string F6(" + modifier + @" 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)); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/73384")] public void Indexer_Override_EscapeInGetter() { var source = """ public ref struct RS { } public class Base { public virtual RS this[scoped RS rs] { get => default; } public virtual RS this[scoped RS rs, int _] { get => default; set { }} } public class C : Base { public override RS this[RS rs] { get => default; } // 1 public override RS this[RS rs, int _] { get => default; set { } } // 2 } """; var comp = CreateCompilation(source); comp.VerifyEmitDiagnostics( // (11,38): error CS8987: The 'scoped' modifier of parameter 'rs' doesn't match overridden or implemented member. // public override RS this[RS rs] { get => default; } // 1 Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfOverrideOrImplementation, "get").WithArguments("rs").WithLocation(11, 38), // (12,45): error CS8987: The 'scoped' modifier of parameter 'rs' doesn't match overridden or implemented member. // public override RS this[RS rs, int _] { get => default; set { } } // 2 Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfOverrideOrImplementation, "get").WithArguments("rs").WithLocation(12, 45)); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/73384")] public void Indexer_InterfaceImplementation_EscapeInGetter() { var source = """ public ref struct RS { } public interface I { public RS this[scoped RS rs] { get; } public RS this[scoped RS rs, int _] { get; set; } } public class C : I { public RS this[RS rs] { get => default; } // 1 public RS this[RS rs, int _] { get => default; set { } } // 2 } """; var comp = CreateCompilation(source); comp.VerifyEmitDiagnostics( // (11,29): error CS8987: The 'scoped' modifier of parameter 'rs' doesn't match overridden or implemented member. // public RS this[RS rs] { get => default; } // 1 Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfOverrideOrImplementation, "get").WithArguments("rs").WithLocation(11, 29), // (12,36): error CS8987: The 'scoped' modifier of parameter 'rs' doesn't match overridden or implemented member. // public RS this[RS rs, int _] { get => default; set { } } // 2 Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfOverrideOrImplementation, "get").WithArguments("rs").WithLocation(12, 36)); } [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,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", sequencePointDisplay: SequencePointDisplayMode.Enhanced, 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( // (3,18): warning CS9265: Field 'R<T>.F' is never ref-assigned to, and will always have its default value (null reference) // public ref T F; Diagnostic(ErrorCode.WRN_UnassignedInternalRefField, "F").WithArguments("R<T>.F").WithLocation(3, 18)); } [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( // (3,27): warning CS9265: Field 'R<T>.F' is never ref-assigned to, and will always have its default value (null reference) // public ref readonly T F; Diagnostic(ErrorCode.WRN_UnassignedInternalRefField, "F").WithArguments("R<T>.F").WithLocation(3, 27), // (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( // 0.cs(16,23): error CS8352: Cannot use variable 'I2 = ref rs.I1' in this context because it may expose referenced variables outside of their declaration scope // rs2 = new RS2 { I2 = ref rs.I1 }; Diagnostic(ErrorCode.ERR_EscapeVariable, "{ I2 = ref rs.I1 }").WithArguments("I2 = ref rs.I1").WithLocation(16, 23)); } [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( // 0.cs(16,23): warning CS9080: Use of variable 'I2 = ref rs.I1' in this context may expose referenced variables outside of their declaration scope // rs2 = new RS2 { I2 = ref rs.I1 }; Diagnostic(ErrorCode.WRN_EscapeVariable, "{ I2 = ref rs.I1 }").WithArguments("I2 = ref rs.I1").WithLocation(16, 23)); } [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,22): error CS8352: Cannot use variable 'refField = ref this.@field' in this context because it may expose referenced variables outside of their declaration scope // S Prop4 => new S { refField = ref this.@field }; // 2 Diagnostic(ErrorCode.ERR_EscapeVariable, "{ refField = ref this.@field }").WithArguments("refField = ref this.@field").WithLocation(18, 22), // (23,21): error CS8352: Cannot use variable 'refField = ref this.field' in this context because it may expose referenced variables outside of their declaration scope // S M1() => new S { refField = ref this.field }; // 3 Diagnostic(ErrorCode.ERR_EscapeVariable, "{ refField = ref this.field }").WithArguments("refField = ref this.field").WithLocation(23, 21), // (28,42): error CS8352: Cannot use variable 'refField = ref s.field' in this context because it may expose referenced variables outside of their declaration scope // static S M3(scoped ref S s) => new S { refField = ref s.field }; // 4 Diagnostic(ErrorCode.ERR_EscapeVariable, "{ refField = ref s.field }").WithArguments("refField = ref s.field").WithLocation(28, 42)); } [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( // (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,23): error CS8352: Cannot use variable 'field = ref x' in this context because it may expose referenced variables outside of their declaration scope // r = new R { field = ref x }; // 2 Diagnostic(ErrorCode.ERR_EscapeVariable, "{ field = ref x }").WithArguments("field = ref x").WithLocation(20, 23), // (29,23): error CS8352: Cannot use variable 'field = ref x' in this context because it may expose referenced variables outside of their declaration scope // r = new R { field = ref x }; // 3 Diagnostic(ErrorCode.ERR_EscapeVariable, "{ field = ref x }").WithArguments("field = ref x").WithLocation(29, 23), // (36,19): error CS8352: Cannot use variable 'field = ref x' in this context because it may expose referenced variables outside of their declaration scope // r = new R { field = ref x }; // 4 Diagnostic(ErrorCode.ERR_EscapeVariable, "{ field = ref x }").WithArguments("field = ref x").WithLocation(36, 19)); // 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,31): error CS8352: Cannot use variable 'item = { field = ref x }' in this context because it may expose referenced variables outside of their declaration scope // r = new Container { item = { field = ref x } }; // 2 Diagnostic(ErrorCode.ERR_EscapeVariable, "{ item = { field = ref x } }").WithArguments("item = { field = ref x }").WithLocation(18, 31), // (25,27): error CS8352: Cannot use variable 'item = { field = ref x }' in this context because it may expose referenced variables outside of their declaration scope // r = new Container { item = { field = ref x } }; // 3 Diagnostic(ErrorCode.ERR_EscapeVariable, "{ item = { field = ref x } }").WithArguments("item = { field = ref x }").WithLocation(25, 27), // (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,30): error CS8352: Cannot use variable 'field = ref x' in this context because it may expose referenced variables outside of their declaration scope // r = new R() with { field = ref x }; // 2 Diagnostic(ErrorCode.ERR_EscapeVariable, "{ field = ref x }").WithArguments("field = ref x").WithLocation(20, 30), // (29,30): error CS8352: Cannot use variable 'field = ref x' in this context because it may expose referenced variables outside of their declaration scope // r = new R() with { field = ref x }; // 3 Diagnostic(ErrorCode.ERR_EscapeVariable, "{ field = ref x }").WithArguments("field = ref x").WithLocation(29, 30), // (36,26): error CS8352: Cannot use variable 'field = ref x' in this context because it may expose referenced variables outside of their declaration scope // r = new R() with { field = ref x }; // 4 Diagnostic(ErrorCode.ERR_EscapeVariable, "{ field = ref x }").WithArguments("field = ref x").WithLocation(36, 26)); } [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 a member declaration // ref scoped R field; Diagnostic(ErrorCode.ERR_InvalidMemberDecl, ";").WithArguments(";").WithLocation(3, 23), // (3,23): error CS1519: Invalid token ';' in a 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,18): error CS0246: The type or namespace name 'Property' 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, "Property").WithArguments("Property").WithLocation(3, 18), // (3,27): error CS1001: Identifier expected // ref scoped R Property { get => throw null; } Diagnostic(ErrorCode.ERR_IdentifierExpected, "{").WithLocation(3, 27)); source = @"ref struct R { void M(ref scoped R parameter) { } }"; comp = CreateCompilation(source); comp.VerifyDiagnostics( // (3,16): error CS9347: The 'scoped' modifier cannot come after an 'in', 'out', 'ref' or 'readonly' modifier. // void M(ref scoped R parameter) Diagnostic(ErrorCode.ERR_ScopedAfterInOutRefReadonly, "scoped").WithLocation(3, 16)); source = @"ref struct R { void M(in scoped R parameter) { } }"; comp = CreateCompilation(source); comp.VerifyDiagnostics( // (3,15): error CS9347: The 'scoped' modifier cannot come after an 'in', 'out', 'ref' or 'readonly' modifier. // void M(in scoped R parameter) Diagnostic(ErrorCode.ERR_ScopedAfterInOutRefReadonly, "scoped").WithLocation(3, 15)); source = @"ref struct R { void M(out scoped R parameter) { } }"; comp = CreateCompilation(source); comp.VerifyDiagnostics( // (3,16): error CS9347: The 'scoped' modifier cannot come after an 'in', 'out', 'ref' or 'readonly' modifier. // void M(out scoped R parameter) Diagnostic(ErrorCode.ERR_ScopedAfterInOutRefReadonly, "scoped").WithLocation(3, 16)); source = @"ref struct R { void M(ref scoped scoped R parameter) { } }"; comp = CreateCompilation(source); comp.VerifyDiagnostics( // (3,16): error CS9347: The 'scoped' modifier cannot come after an 'in', 'out', 'ref' or 'readonly' modifier. // void M(ref scoped scoped R parameter) Diagnostic(ErrorCode.ERR_ScopedAfterInOutRefReadonly, "scoped").WithLocation(3, 16), // (3,23): error CS1107: A parameter can only have one 'scoped' modifier // void M(ref scoped scoped R parameter) Diagnostic(ErrorCode.ERR_DupParamMod, "scoped").WithArguments("scoped").WithLocation(3, 23)); 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( // (1,12): error CS8983: A 'struct' with field initializers must include an explicitly declared constructor. // ref struct R Diagnostic(ErrorCode.ERR_StructHasInitializersAndNoDeclaredConstructor, "R").WithLocation(1, 12), // (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 CS1003: Syntax error, '=' expected // ref scoped R M() => throw null; Diagnostic(ErrorCode.ERR_SyntaxError, "M").WithArguments("=").WithLocation(3, 18), // (3,18): error CS8172: Cannot initialize a by-reference variable with a value // ref scoped R M() => throw null; Diagnostic(ErrorCode.ERR_InitializeByReferenceVariableWithValue, "M() => throw null").WithLocation(3, 18), // (3,18): error CS0246: The type or namespace name 'M' could not be found (are you missing a using directive or an assembly reference?) // ref scoped R M() => throw null; Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "M").WithArguments("M").WithLocation(3, 18), // (3,18): error CS1510: A ref or out value must be an assignable variable // ref scoped R M() => throw null; Diagnostic(ErrorCode.ERR_RefLvalueExpected, "M() => throw null").WithLocation(3, 18)); source = @" delegate void M(ref scoped R parameter); ref struct R { } "; comp = CreateCompilation(source); comp.VerifyDiagnostics( // (2,21): error CS9347: The 'scoped' modifier cannot come after an 'in', 'out', 'ref' or 'readonly' modifier. // delegate void M(ref scoped R parameter); Diagnostic(ErrorCode.ERR_ScopedAfterInOutRefReadonly, "scoped").WithLocation(2, 21)); source = @" ref struct R { void M() { _ = void (ref scoped R parameter) => throw null; } } "; comp = CreateCompilation(source); comp.VerifyDiagnostics( // (6,9): error CS8183: Cannot infer the type of implicitly-typed discard. // _ = void (ref scoped R parameter) => throw null; Diagnostic(ErrorCode.ERR_DiscardTypeInferenceFailed, "_").WithLocation(6, 9), // (6,23): error CS9347: The 'scoped' modifier cannot come after an 'in', 'out', 'ref' or 'readonly' modifier. // _ = void (ref scoped R parameter) => throw null; Diagnostic(ErrorCode.ERR_ScopedAfterInOutRefReadonly, "scoped").WithLocation(6, 23)); } [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) ); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/75828")] public void UnscopedRefAttribute_RefSafetyRules_ThisParameter() { var source = """ using System.Diagnostics.CodeAnalysis; struct S { public int F; [UnscopedRef] public ref int Ref() => ref F; } """; CreateCompilation([source, UnscopedRefAttributeDefinition], parseOptions: TestOptions.Regular10).VerifyDiagnostics( // (6,6): warning CS9269: UnscopedRefAttribute is only valid in C# 11 or later or when targeting net7.0 or later. // [UnscopedRef] public ref int Ref() => ref F; Diagnostic(ErrorCode.WRN_UnscopedRefAttributeOldRules, "UnscopedRef").WithLocation(6, 6), // (6,47): error CS8170: Struct members cannot return 'this' or other instance members by reference // [UnscopedRef] public ref int Ref() => ref F; Diagnostic(ErrorCode.ERR_RefReturnStructThis, "F").WithLocation(6, 47)); CreateCompilation(source, parseOptions: TestOptions.Regular10, targetFramework: TargetFramework.Net70).VerifyDiagnostics(); CreateCompilation([source, UnscopedRefAttributeDefinition], parseOptions: TestOptions.Regular11).VerifyDiagnostics(); CreateCompilation([source, UnscopedRefAttributeDefinition]).VerifyDiagnostics(); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/75828")] public void UnscopedRefAttribute_RefSafetyRules_ThisParameter_Property() { var source = """ using System.Diagnostics.CodeAnalysis; struct S { public int F; [UnscopedRef] public ref int Ref => ref F; } """; CreateCompilation([source, UnscopedRefAttributeDefinition], parseOptions: TestOptions.Regular10).VerifyDiagnostics( // (6,6): warning CS9269: UnscopedRefAttribute is only valid in C# 11 or later or when targeting net7.0 or later. // [UnscopedRef] public ref int Ref => ref F; Diagnostic(ErrorCode.WRN_UnscopedRefAttributeOldRules, "UnscopedRef").WithLocation(6, 6), // (6,45): error CS8170: Struct members cannot return 'this' or other instance members by reference // [UnscopedRef] public ref int Ref => ref F; Diagnostic(ErrorCode.ERR_RefReturnStructThis, "F").WithLocation(6, 45)); CreateCompilation(source, parseOptions: TestOptions.Regular10, targetFramework: TargetFramework.Net70).VerifyDiagnostics(); CreateCompilation([source, UnscopedRefAttributeDefinition], parseOptions: TestOptions.Regular11).VerifyDiagnostics(); CreateCompilation([source, UnscopedRefAttributeDefinition]).VerifyDiagnostics(); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/75828")] public void UnscopedRefAttribute_RefSafetyRules_RefParameter() { var source = """ using System.Diagnostics.CodeAnalysis; class C { void M([UnscopedRef] ref int x, out int y) { y = default; x = ref y; } } """; CreateCompilation([source, UnscopedRefAttributeDefinition], parseOptions: TestOptions.Regular10).VerifyDiagnostics( // (4,13): warning CS9269: UnscopedRefAttribute is only valid in C# 11 or later or when targeting net7.0 or later. // void M([UnscopedRef] ref int x, out int y) Diagnostic(ErrorCode.WRN_UnscopedRefAttributeOldRules, "UnscopedRef").WithLocation(4, 13)); var expectedDiagnostics = new[] { // (7,9): error CS8374: Cannot ref-assign 'y' to 'x' because 'y' has a narrower escape scope than 'x'. // x = ref y; Diagnostic(ErrorCode.ERR_RefAssignNarrower, "x = ref y").WithArguments("x", "y").WithLocation(7, 9) }; CreateCompilation(source, parseOptions: TestOptions.Regular10, targetFramework: TargetFramework.Net70).VerifyDiagnostics(expectedDiagnostics); CreateCompilation([source, UnscopedRefAttributeDefinition], parseOptions: TestOptions.Regular11).VerifyDiagnostics(expectedDiagnostics); CreateCompilation([source, UnscopedRefAttributeDefinition]).VerifyDiagnostics(expectedDiagnostics); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/75828")] public void UnscopedRefAttribute_RefSafetyRules_OutParameter() { var source = """ using System.Diagnostics.CodeAnalysis; struct S { public int F; public static ref int Ref([UnscopedRef] out S s) { s = default; return ref s.F; } } """; CreateCompilation([source, UnscopedRefAttributeDefinition], parseOptions: TestOptions.Regular10).VerifyDiagnostics( // (6,32): warning CS9269: UnscopedRefAttribute is only valid in C# 11 or later or when targeting net7.0 or later. // public static ref int Ref([UnscopedRef] out S s) Diagnostic(ErrorCode.WRN_UnscopedRefAttributeOldRules, "UnscopedRef").WithLocation(6, 32)); CreateCompilation(source, parseOptions: TestOptions.Regular10, targetFramework: TargetFramework.Net70).VerifyDiagnostics(); CreateCompilation([source, UnscopedRefAttributeDefinition], parseOptions: TestOptions.Regular11).VerifyDiagnostics(); CreateCompilation([source, UnscopedRefAttributeDefinition]).VerifyDiagnostics(); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/75828")] public void UnscopedRefAttribute_RefSafetyRules_ScopedParameter() { var source = """ using System.Diagnostics.CodeAnalysis; struct S { public int F; public static ref int Ref([UnscopedRef] scoped ref S s) => ref s.F; } """; CreateCompilation([source, UnscopedRefAttributeDefinition], parseOptions: TestOptions.Regular10).VerifyDiagnostics( // (6,32): warning CS9269: UnscopedRefAttribute is only valid in C# 11 or later or when targeting net7.0 or later. // public static ref int Ref([UnscopedRef] scoped ref S s) => ref s.F; Diagnostic(ErrorCode.WRN_UnscopedRefAttributeOldRules, "UnscopedRef").WithLocation(6, 32), // (6,32): error CS9066: UnscopedRefAttribute cannot be applied to parameters that have a 'scoped' modifier. // public static ref int Ref([UnscopedRef] scoped ref S s) => ref s.F; Diagnostic(ErrorCode.ERR_UnscopedScoped, "UnscopedRef").WithLocation(6, 32), // (6,45): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater. // public static ref int Ref([UnscopedRef] scoped ref S s) => ref s.F; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "scoped").WithArguments("ref fields", "11.0").WithLocation(6, 45), // (6,68): error CS9076: Cannot return by reference a member of parameter 's' because it is scoped to the current method // public static ref int Ref([UnscopedRef] scoped ref S s) => ref s.F; Diagnostic(ErrorCode.ERR_RefReturnScopedParameter2, "s").WithArguments("s").WithLocation(6, 68)); CreateCompilation(source, parseOptions: TestOptions.Regular10, targetFramework: TargetFramework.Net70).VerifyDiagnostics( // (6,32): error CS9066: UnscopedRefAttribute cannot be applied to parameters that have a 'scoped' modifier. // public static ref int Ref([UnscopedRef] scoped ref S s) => ref s.F; Diagnostic(ErrorCode.ERR_UnscopedScoped, "UnscopedRef").WithLocation(6, 32), // (6,45): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater. // public static ref int Ref([UnscopedRef] scoped ref S s) => ref s.F; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "scoped").WithArguments("ref fields", "11.0").WithLocation(6, 45)); var expectedDiagnostics = new[] { // (6,32): error CS9066: UnscopedRefAttribute cannot be applied to parameters that have a 'scoped' modifier. // public static ref int Ref([UnscopedRef] scoped ref S s) => ref s.F; Diagnostic(ErrorCode.ERR_UnscopedScoped, "UnscopedRef").WithLocation(6, 32) }; CreateCompilation([source, UnscopedRefAttributeDefinition], parseOptions: TestOptions.Regular11).VerifyDiagnostics(expectedDiagnostics); CreateCompilation([source, UnscopedRefAttributeDefinition]).VerifyDiagnostics(expectedDiagnostics); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/75828")] public void UnscopedRefAttribute_RefSafetyRules_Reference() { var source1 = """ using System.Diagnostics.CodeAnalysis; public struct S { [UnscopedRef] public ref int Ref() => throw null; } """; var ref1a = CreateCompilation([source1, UnscopedRefAttributeDefinition], parseOptions: TestOptions.Regular10).VerifyDiagnostics( // (4,6): warning CS9269: UnscopedRefAttribute is only valid in C# 11 or later or when targeting net7.0 or later. // [UnscopedRef] public ref int Ref() => throw null; Diagnostic(ErrorCode.WRN_UnscopedRefAttributeOldRules, "UnscopedRef").WithLocation(4, 6)).EmitToImageReference(); var ref1b = CreateCompilation(source1, parseOptions: TestOptions.Regular10, targetFramework: TargetFramework.Net70).VerifyDiagnostics().EmitToImageReference(); var ref1c = CreateCompilation([source1, UnscopedRefAttributeDefinition], parseOptions: TestOptions.Regular11).VerifyDiagnostics().EmitToImageReference(); var ref1d = CreateCompilation([source1, UnscopedRefAttributeDefinition]).VerifyDiagnostics().EmitToImageReference(); var source2 = """ static class C { static ref int M() { S s = default; return ref s.Ref(); } } """; CreateCompilation(source2, [ref1a], parseOptions: TestOptions.Regular10).VerifyDiagnostics(); CreateCompilation(source2, [ref1a], parseOptions: TestOptions.Regular10, targetFramework: TargetFramework.Net70).VerifyDiagnostics(); CreateCompilation(source2, [ref1a], parseOptions: TestOptions.Regular11).VerifyDiagnostics(); CreateCompilation(source2, [ref1a]).VerifyDiagnostics(); foreach (var ref1 in new[] { ref1b, ref1c, ref1d }) { var expectedDiagnostics = new[] { // (6,20): error CS8168: Cannot return local 's' by reference because it is not a ref local // return ref s.Ref(); Diagnostic(ErrorCode.ERR_RefReturnLocal, "s").WithArguments("s").WithLocation(6, 20) }; CreateCompilation(source2, [ref1], parseOptions: TestOptions.Regular10).VerifyDiagnostics(expectedDiagnostics); CreateCompilation(source2, [ref1], parseOptions: TestOptions.Regular10, targetFramework: TargetFramework.Net70).VerifyDiagnostics(expectedDiagnostics); CreateCompilation(source2, [ref1], parseOptions: TestOptions.Regular11).VerifyDiagnostics(expectedDiagnostics); CreateCompilation(source2, [ref1]).VerifyDiagnostics(expectedDiagnostics); } } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/75828")] public void UnscopedRefAttribute_RefSafetyRules_Reference_Property() { var source1 = """ using System.Diagnostics.CodeAnalysis; public struct S { [UnscopedRef] public ref int Ref => throw null; } """; var ref1a = CreateCompilation([source1, UnscopedRefAttributeDefinition], parseOptions: TestOptions.Regular10).VerifyDiagnostics( // (4,6): warning CS9269: UnscopedRefAttribute is only valid in C# 11 or later or when targeting net7.0 or later. // [UnscopedRef] public ref int Ref => throw null; Diagnostic(ErrorCode.WRN_UnscopedRefAttributeOldRules, "UnscopedRef").WithLocation(4, 6)).EmitToImageReference(); var ref1b = CreateCompilation(source1, parseOptions: TestOptions.Regular10, targetFramework: TargetFramework.Net70).VerifyDiagnostics().EmitToImageReference(); var ref1c = CreateCompilation([source1, UnscopedRefAttributeDefinition], parseOptions: TestOptions.Regular11).VerifyDiagnostics().EmitToImageReference(); var ref1d = CreateCompilation([source1, UnscopedRefAttributeDefinition]).VerifyDiagnostics().EmitToImageReference(); var source2 = """ static class C { static ref int M() { S s = default; return ref s.Ref; } } """; CreateCompilation(source2, [ref1a], parseOptions: TestOptions.Regular10).VerifyDiagnostics(); CreateCompilation(source2, [ref1a], parseOptions: TestOptions.Regular10, targetFramework: TargetFramework.Net70).VerifyDiagnostics(); CreateCompilation(source2, [ref1a], parseOptions: TestOptions.Regular11).VerifyDiagnostics(); CreateCompilation(source2, [ref1a]).VerifyDiagnostics(); foreach (var ref1 in new[] { ref1b, ref1c, ref1d }) { var expectedDiagnostics = new[] { // (6,20): error CS8168: Cannot return local 's' by reference because it is not a ref local // return ref s.Ref(); Diagnostic(ErrorCode.ERR_RefReturnLocal, "s").WithArguments("s").WithLocation(6, 20) }; CreateCompilation(source2, [ref1], parseOptions: TestOptions.Regular10).VerifyDiagnostics(expectedDiagnostics); CreateCompilation(source2, [ref1], parseOptions: TestOptions.Regular10, targetFramework: TargetFramework.Net70).VerifyDiagnostics(expectedDiagnostics); CreateCompilation(source2, [ref1], parseOptions: TestOptions.Regular11).VerifyDiagnostics(expectedDiagnostics); CreateCompilation(source2, [ref1]).VerifyDiagnostics(expectedDiagnostics); } } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/75828")] public void UnscopedRefAttribute_RefSafetyRules_Reference_SynthesizedDelegate_01() { var source1 = """ using System.Diagnostics.CodeAnalysis; public static class C { public static void M([UnscopedRef] ref int x) { } } """; var ref1 = CreateCompilation([source1, UnscopedRefAttributeDefinition]) .VerifyDiagnostics().EmitToImageReference(); var source2 = """ using System; Delegate d = C.M; Console.WriteLine(d.GetType()); """; var expectedOutput = "<>f__AnonymousDelegate0"; CompileAndVerify(source2, [ref1], parseOptions: TestOptions.Regular10, symbolValidator: validate, expectedOutput: expectedOutput).VerifyDiagnostics(); CompileAndVerify(source2, [ref1], symbolValidator: validate, expectedOutput: expectedOutput).VerifyDiagnostics(); static void validate(ModuleSymbol module) { var m = module.GlobalNamespace.GetMember<MethodSymbol>("<>f__AnonymousDelegate0.Invoke"); AssertEx.Equal("void <>f__AnonymousDelegate0.Invoke(ref System.Int32 arg)", m.ToTestDisplayString()); var a = m.Parameters[0].GetAttributes().Single().AttributeClass.ToTestDisplayString(); AssertEx.Equal("System.Diagnostics.CodeAnalysis.UnscopedRefAttribute", a); } } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/75828")] public void UnscopedRefAttribute_RefSafetyRules_Reference_SynthesizedDelegate_02() { var source1 = """ using System.Diagnostics.CodeAnalysis; public static class C { public static void M([UnscopedRef] ref int x) { } } """; var ref1 = CreateCompilation([source1, UnscopedRefAttributeDefinition], parseOptions: TestOptions.Regular10) .VerifyDiagnostics( // (4,27): warning CS9269: UnscopedRefAttribute is only valid in C# 11 or later or when targeting net7.0 or later. // public static void M([UnscopedRef] ref int x) { } Diagnostic(ErrorCode.WRN_UnscopedRefAttributeOldRules, "UnscopedRef").WithLocation(4, 27)) .EmitToImageReference(); var source2 = """ using System; Delegate d = C.M; Console.WriteLine(d.GetType()); """; var expectedOutput = "<>A{00000001}`1[System.Int32]"; CompileAndVerify(source2, [ref1], parseOptions: TestOptions.Regular10, symbolValidator: validate, expectedOutput: expectedOutput).VerifyDiagnostics(); CompileAndVerify(source2, [ref1], symbolValidator: validate, expectedOutput: expectedOutput).VerifyDiagnostics(); static void validate(ModuleSymbol module) { var m = module.GlobalNamespace.GetMember<MethodSymbol>("<>A{00000001}.Invoke"); AssertEx.Equal("void <>A{00000001}<T1>.Invoke(ref T1 arg)", m.ToTestDisplayString()); Assert.Empty(m.Parameters[0].GetAttributes()); } } [Fact] [WorkItem("https://github.com/dotnet/roslyn/issues/75828")] [WorkItem("https://github.com/dotnet/roslyn/issues/76087")] public void UnscopedRefAttribute_RefSafetyRules_Reference_SynthesizedDelegate_03() { var source1 = """ using System.Diagnostics.CodeAnalysis; public static class C { public static void M([UnscopedRef] ref int x, ref R r) { r.F = ref x; } } public ref struct R { public ref int F; } """; var ref1 = CreateCompilation(source1, targetFramework: TargetFramework.Net70) .VerifyDiagnostics().EmitToImageReference(); var source2 = """ int x = 1; R r = default; C.M(ref x, ref r); var d = C.M; d(ref x, ref r); """; // Should the delegate invocation be an error as well? https://github.com/dotnet/roslyn/issues/76087 CreateCompilation([source2, UnscopedRefAttributeDefinition], [ref1], parseOptions: TestOptions.Regular10).VerifyDiagnostics( // (3,1): error CS8350: This combination of arguments to 'C.M(ref int, ref R)' is disallowed because it may expose variables referenced by parameter 'x' outside of their declaration scope // C.M(ref x, ref r); Diagnostic(ErrorCode.ERR_CallArgMixing, "C.M(ref x, ref r)").WithArguments("C.M(ref int, ref R)", "x").WithLocation(3, 1), // (3,9): error CS8168: Cannot return local 'x' by reference because it is not a ref local // C.M(ref x, ref r); Diagnostic(ErrorCode.ERR_RefReturnLocal, "x").WithArguments("x").WithLocation(3, 9)); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/75828")] public void UnscopedRefAttribute_InvalidLocation_Parameter() { var source = """ using System.Diagnostics.CodeAnalysis; class C { ref T F1<T>([UnscopedRef] R<T> r) => throw null; ref T F2<T>([UnscopedRef] T r) => throw null; } ref struct R<T> { } """; CreateCompilation([source, UnscopedRefAttributeDefinition], parseOptions: TestOptions.Regular10).VerifyDiagnostics( // (4,18): warning CS9269: UnscopedRefAttribute is only valid in C# 11 or later or when targeting net7.0 or later. // ref T F1<T>([UnscopedRef] R<T> r) => throw null; Diagnostic(ErrorCode.WRN_UnscopedRefAttributeOldRules, "UnscopedRef").WithLocation(4, 18), // (4,18): error CS9063: UnscopedRefAttribute cannot be applied to this parameter because it is unscoped by default. // ref T F1<T>([UnscopedRef] R<T> r) => throw null; Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedTarget, "UnscopedRef").WithLocation(4, 18), // (5,18): warning CS9269: UnscopedRefAttribute is only valid in C# 11 or later or when targeting net7.0 or later. // ref T F2<T>([UnscopedRef] T r) => throw null; Diagnostic(ErrorCode.WRN_UnscopedRefAttributeOldRules, "UnscopedRef").WithLocation(5, 18), // (5,18): error CS9063: UnscopedRefAttribute cannot be applied to this parameter because it is unscoped by default. // ref T F2<T>([UnscopedRef] T r) => throw null; Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedTarget, "UnscopedRef").WithLocation(5, 18)); var expectedDiagnostics = new[] { // (4,18): error CS9063: UnscopedRefAttribute cannot be applied to this parameter because it is unscoped by default. // ref T F1<T>([UnscopedRef] R<T> r) => throw null; Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedTarget, "UnscopedRef").WithLocation(4, 18), // (5,18): error CS9063: UnscopedRefAttribute cannot be applied to this parameter because it is unscoped by default. // ref T F2<T>([UnscopedRef] T r) => throw null; Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedTarget, "UnscopedRef").WithLocation(5, 18) }; CreateCompilation(source, parseOptions: TestOptions.Regular10, targetFramework: TargetFramework.Net70).VerifyDiagnostics(expectedDiagnostics); CreateCompilation([source, UnscopedRefAttributeDefinition], parseOptions: TestOptions.Regular11).VerifyDiagnostics(expectedDiagnostics); CreateCompilation([source, UnscopedRefAttributeDefinition]).VerifyDiagnostics(expectedDiagnostics); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/75828")] public void UnscopedRefAttribute_InvalidLocation_Method() { var source = """ using System.Diagnostics.CodeAnalysis; class C { [UnscopedRef] object F() => null; } """; CreateCompilation([source, UnscopedRefAttributeDefinition], parseOptions: TestOptions.Regular10).VerifyDiagnostics( // (4,6): warning CS9269: UnscopedRefAttribute is only valid in C# 11 or later or when targeting net7.0 or later. // [UnscopedRef] object F() => null; Diagnostic(ErrorCode.WRN_UnscopedRefAttributeOldRules, "UnscopedRef").WithLocation(4, 6), // (4,6): error CS9101: UnscopedRefAttribute can only be applied to struct or virtual interface instance methods and properties, and cannot be applied to constructors or init-only members. // [UnscopedRef] object F() => null; Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(4, 6)); var expectedDiagnostics = new[] { // (4,6): error CS9101: UnscopedRefAttribute can only be applied to struct or virtual interface instance methods and properties, and cannot be applied to constructors or init-only members. // [UnscopedRef] object F() => null; Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(4, 6) }; CreateCompilation(source, parseOptions: TestOptions.Regular10, targetFramework: TargetFramework.Net70).VerifyDiagnostics(expectedDiagnostics); CreateCompilation([source, UnscopedRefAttributeDefinition], parseOptions: TestOptions.Regular11).VerifyDiagnostics(expectedDiagnostics); CreateCompilation([source, UnscopedRefAttributeDefinition]).VerifyDiagnostics(expectedDiagnostics); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/75828")] public void UnscopedRefAttribute_InvalidLocation_Property() { var source = """ using System.Diagnostics.CodeAnalysis; struct S { [UnscopedRef] object P { get; init; } } """; CreateCompilation([source, UnscopedRefAttributeDefinition, IsExternalInitTypeDefinition], parseOptions: TestOptions.Regular10).VerifyDiagnostics( // (4,6): warning CS9269: UnscopedRefAttribute is only valid in C# 11 or later or when targeting net7.0 or later. // [UnscopedRef] object P { get; init; } Diagnostic(ErrorCode.WRN_UnscopedRefAttributeOldRules, "UnscopedRef").WithLocation(4, 6), // (4,6): error CS9101: UnscopedRefAttribute can only be applied to struct or virtual interface instance methods and properties, and cannot be applied to constructors or init-only members. // [UnscopedRef] object P { get; init; } Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(4, 6)); var expectedDiagnostics = new[] { // (4,6): error CS9101: UnscopedRefAttribute can only be applied to struct or virtual interface instance methods and properties, and cannot be applied to constructors or init-only members. // [UnscopedRef] object P { get; init; } Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(4, 6) }; CreateCompilation(source, parseOptions: TestOptions.Regular10, targetFramework: TargetFramework.Net70).VerifyDiagnostics(expectedDiagnostics); CreateCompilation([source, UnscopedRefAttributeDefinition, IsExternalInitTypeDefinition], parseOptions: TestOptions.Regular11).VerifyDiagnostics(expectedDiagnostics); CreateCompilation([source, UnscopedRefAttributeDefinition, IsExternalInitTypeDefinition]).VerifyDiagnostics(expectedDiagnostics); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/76087")] public void RefSafetyRules_SynthesizedDelegate() { var source1 = """ public static class C { public static R M(ref int x) => new R { F = ref x }; } public ref struct R { public ref int F; } """; var ref1 = CreateCompilation(source1, targetFramework: TargetFramework.Net70) .VerifyDiagnostics().EmitToImageReference(); var source2 = """ R r; { int x = 1; r = C.M(ref x); var d = C.M; r = d(ref x); } """; // Should the delegate invocation be an error as well? https://github.com/dotnet/roslyn/issues/76087 CreateCompilation(source2, [ref1], parseOptions: TestOptions.Regular10).VerifyDiagnostics( // (4,9): error CS8347: Cannot use a result of 'C.M(ref int)' in this context because it may expose variables referenced by parameter 'x' outside of their declaration scope // r = C.M(ref x); Diagnostic(ErrorCode.ERR_EscapeCall, "C.M(ref x)").WithArguments("C.M(ref int)", "x").WithLocation(4, 9), // (4,17): error CS8168: Cannot return local 'x' by reference because it is not a ref local // r = C.M(ref x); Diagnostic(ErrorCode.ERR_RefReturnLocal, "x").WithArguments("x").WithLocation(4, 17)); } [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 or virtual interface 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 or virtual interface 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 or virtual interface 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 or virtual interface 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 or virtual interface 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 or virtual interface 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 or virtual interface 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 or virtual interface 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 or virtual interface 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 or virtual interface 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 or virtual interface 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 or virtual interface 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 or virtual interface 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 or virtual interface 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 or virtual interface 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 or virtual interface 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 or virtual interface 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.Mscorlib461); 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 or virtual interface 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 or virtual interface 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 or virtual interface 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 or virtual interface 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 or virtual interface 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 or virtual interface 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 or virtual interface 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( // (5,6): warning CS9269: UnscopedRefAttribute is only valid in C# 11 or later or when targeting net7.0 or later. // [UnscopedRef] ref int F() => throw null; Diagnostic(ErrorCode.WRN_UnscopedRefAttributeOldRules, "UnscopedRef").WithLocation(5, 6), // (6,6): warning CS9269: UnscopedRefAttribute is only valid in C# 11 or later or when targeting net7.0 or later. // [UnscopedRef] ref int P => throw null; Diagnostic(ErrorCode.WRN_UnscopedRefAttributeOldRules, "UnscopedRef").WithLocation(6, 6), // (10,21): warning CS9269: UnscopedRefAttribute is only valid in C# 11 or later or when targeting net7.0 or later. // static void F1([UnscopedRef] out int i1) { i1 = 0; } Diagnostic(ErrorCode.WRN_UnscopedRefAttributeOldRules, "UnscopedRef").WithLocation(10, 21), // (11,21): warning CS9269: UnscopedRefAttribute is only valid in C# 11 or later or when targeting net7.0 or later. // static void F2([UnscopedRef] R r2) { } Diagnostic(ErrorCode.WRN_UnscopedRefAttributeOldRules, "UnscopedRef").WithLocation(11, 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): warning CS9269: UnscopedRefAttribute is only valid in C# 11 or later or when targeting net7.0 or later. // static void F3([UnscopedRef] ref R r3) { } Diagnostic(ErrorCode.WRN_UnscopedRefAttributeOldRules, "UnscopedRef").WithLocation(12, 21), // (13,21): warning CS9269: UnscopedRefAttribute is only valid in C# 11 or later or when targeting net7.0 or later. // static void F4([UnscopedRef] in R r4) { } Diagnostic(ErrorCode.WRN_UnscopedRefAttributeOldRules, "UnscopedRef").WithLocation(13, 21), // (14,21): warning CS9269: UnscopedRefAttribute is only valid in C# 11 or later or when targeting net7.0 or later. // static void F5([UnscopedRef] out R r5) { } Diagnostic(ErrorCode.WRN_UnscopedRefAttributeOldRules, "UnscopedRef").WithLocation(14, 21)); } var scopedRefInCSharp10 = languageVersion == LanguageVersion.CSharp11 ? ScopedKind.None : ScopedKind.ScopedRef; VerifyParameterSymbol(comp.GetMember<MethodSymbol>("S.F").ThisParameter, "ref S this", RefKind.Ref, scopedRefInCSharp10, expectedHasUnscopedRefAttribute: true); VerifyParameterSymbol(comp.GetMember<PropertySymbol>("S.P").GetMethod.ThisParameter, "ref S this", RefKind.Ref, scopedRefInCSharp10, 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 because implemented member 'I<int>.F1()' doesn't have this attribute. // [UnscopedRef] public ref int F1() => ref _f2; // 1 Diagnostic(ErrorCode.ERR_UnscopedRefAttributeInterfaceImplementation, "F1").WithArguments("I<int>.F1()").WithLocation(23, 34), // (24,31): error CS9102: UnscopedRefAttribute cannot be applied to an interface implementation because implemented member 'I<int>.F2()' doesn't have this attribute. // [UnscopedRef] public void F2() { } // 2 Diagnostic(ErrorCode.ERR_UnscopedRefAttributeInterfaceImplementation, "F2").WithArguments("I<int>.F2()").WithLocation(24, 31), // (25,31): error CS9102: UnscopedRefAttribute cannot be applied to an interface implementation because implemented member 'I<int>.F3(out R<int>)' doesn't have this attribute. // [UnscopedRef] public void F3(out R<int> r) { r = new R<int>(ref _f2); } // 3 Diagnostic(ErrorCode.ERR_UnscopedRefAttributeInterfaceImplementation, "F3").WithArguments("I<int>.F3(out R<int>)").WithLocation(25, 31), // (26,39): error CS9102: UnscopedRefAttribute cannot be applied to an interface implementation because implemented member 'I<int>.P.get' doesn't have this attribute. // [UnscopedRef] public ref int P => ref _f2; // 4 Diagnostic(ErrorCode.ERR_UnscopedRefAttributeInterfaceImplementation, "ref _f2").WithArguments("I<int>.P.get").WithLocation(26, 39), // (38,34): error CS9102: UnscopedRefAttribute cannot be applied to an interface implementation because implemented member 'I<int>.F1()' doesn't have this attribute. // [UnscopedRef] ref int I<int>.F1() => ref _f4; // 5 Diagnostic(ErrorCode.ERR_UnscopedRefAttributeInterfaceImplementation, "F1").WithArguments("I<int>.F1()").WithLocation(38, 34), // (39,31): error CS9102: UnscopedRefAttribute cannot be applied to an interface implementation because implemented member 'I<int>.F2()' doesn't have this attribute. // [UnscopedRef] void I<int>.F2() { } // 6 Diagnostic(ErrorCode.ERR_UnscopedRefAttributeInterfaceImplementation, "F2").WithArguments("I<int>.F2()").WithLocation(39, 31), // (40,31): error CS9102: UnscopedRefAttribute cannot be applied to an interface implementation because implemented member 'I<int>.F3(out R<int>)' doesn't have this attribute. // [UnscopedRef] void I<int>.F3(out R<int> r) { r = new R<int>(ref _f4); } // 7 Diagnostic(ErrorCode.ERR_UnscopedRefAttributeInterfaceImplementation, "F3").WithArguments("I<int>.F3(out R<int>)").WithLocation(40, 31), // (41,39): error CS9102: UnscopedRefAttribute cannot be applied to an interface implementation because implemented member 'I<int>.P.get' doesn't have this attribute. // [UnscopedRef] ref int I<int>.P => ref _f4; // 8 Diagnostic(ErrorCode.ERR_UnscopedRefAttributeInterfaceImplementation, "ref _f4").WithArguments("I<int>.P.get").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(); [UnscopedRef] void F2(); [UnscopedRef] void F3(out R<T> r); [UnscopedRef] 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; [UnscopedRef] public void F2() { } [UnscopedRef] public void F3(out R<int> r) { r = new R<int>(ref _f2); } [UnscopedRef] public ref int P => ref _f2; } 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; [UnscopedRef] void I<int>.F2() { } [UnscopedRef] void I<int>.F3(out R<int> r) { r = new R<int>(ref _f4); } [UnscopedRef] ref int I<int>.P => ref _f4; } """; var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70); comp.VerifyEmitDiagnostics(); } [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 because implemented member 'I1<int>.P1.get' doesn't have this attribute. // [UnscopedRef] public ref int P1 => throw null; // 1 Diagnostic(ErrorCode.ERR_UnscopedRefAttributeInterfaceImplementation, "throw null").WithArguments("I1<int>.P1.get").WithLocation(16, 40), // (17,35): error CS9102: UnscopedRefAttribute cannot be applied to an interface implementation because implemented member 'I2<int>.P2.get' doesn't have this attribute. // [UnscopedRef] public int P2 { get; set; } // 2, 3 Diagnostic(ErrorCode.ERR_UnscopedRefAttributeInterfaceImplementation, "get").WithArguments("I2<int>.P2.get").WithLocation(17, 35), // (17,40): error CS9102: UnscopedRefAttribute cannot be applied to an interface implementation because implemented member 'I2<int>.P2.set' doesn't have this attribute. // [UnscopedRef] public int P2 { get; set; } // 2, 3 Diagnostic(ErrorCode.ERR_UnscopedRefAttributeInterfaceImplementation, "set").WithArguments("I2<int>.P2.set").WithLocation(17, 40), // (21,39): error CS9102: UnscopedRefAttribute cannot be applied to an interface implementation because implemented member 'I1<int>.P1.get' doesn't have this attribute. // public ref int P1 { [UnscopedRef] get => throw null; } // 4 Diagnostic(ErrorCode.ERR_UnscopedRefAttributeInterfaceImplementation, "get").WithArguments("I1<int>.P1.get").WithLocation(21, 39), // (22,35): error CS9102: UnscopedRefAttribute cannot be applied to an interface implementation because implemented member 'I2<int>.P2.get' doesn't have this attribute. // public int P2 { [UnscopedRef] get; set; } // 5 Diagnostic(ErrorCode.ERR_UnscopedRefAttributeInterfaceImplementation, "get").WithArguments("I2<int>.P2.get").WithLocation(22, 35), // (26,40): error CS9102: UnscopedRefAttribute cannot be applied to an interface implementation because implemented member 'I2<int>.P2.set' doesn't have this attribute. // public int P2 { get; [UnscopedRef] set; } // 6 Diagnostic(ErrorCode.ERR_UnscopedRefAttributeInterfaceImplementation, "set").WithArguments("I2<int>.P2.set").WithLocation(26, 40), // (27,35): error CS9102: UnscopedRefAttribute cannot be applied to an interface implementation because implemented member 'I3<int>.P3.set' doesn't have this attribute. // public int P3 { [UnscopedRef] set { } } // 7 Diagnostic(ErrorCode.ERR_UnscopedRefAttributeInterfaceImplementation, "set").WithArguments("I3<int>.P3.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(); } 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( // (10,6): error CS9101: UnscopedRefAttribute can only be applied to struct or virtual interface 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 or virtual interface 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 or virtual interface 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 or virtual interface 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 or virtual interface 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 or virtual interface 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 or virtual interface 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 or virtual interface 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 or virtual interface 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 or virtual interface 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 or virtual interface 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 or virtual interface 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 or virtual interface 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 or virtual interface 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 or virtual interface 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 or virtual interface 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 or virtual interface 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 or virtual interface 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 or virtual interface 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 or virtual interface 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 or virtual interface 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 or virtual interface 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 or virtual interface 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 or virtual interface 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 or virtual interface 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 or virtual interface 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 or virtual interface 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 or virtual interface 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 or virtual interface 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 or virtual interface 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 or virtual interface 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 or virtual interface 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 or virtual interface 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 or virtual interface 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 or virtual interface 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 or virtual interface 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 or virtual interface 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 or virtual interface 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 or virtual interface 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 or virtual interface 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 or virtual interface 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 or virtual interface 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 or virtual interface 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 or virtual interface 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 or virtual interface 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 or virtual interface 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 or virtual interface 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 or virtual interface 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 or virtual interface 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)); } [Theory, CombinatorialData, WorkItem("https://github.com/dotnet/roslyn/issues/67697")] public void UnscopedRefAttribute_NestedAccess_MethodOrProperty(bool firstIsMethod, bool secondIsMethod) { var source = $$""" using System.Diagnostics.CodeAnalysis; var c = new C(); c.Value() = 12; System.Console.WriteLine(c.Value()); class C { private S1 s1; public ref int Value() => ref s1.S2{{csharp(firstIsMethod)}}.Value{{csharp(secondIsMethod)}}; } struct S1 { private S2 s2; [UnscopedRef] public ref S2 S2{{csharp(firstIsMethod)}} => ref s2; } struct S2 { private int value; [UnscopedRef] public ref int Value{{csharp(secondIsMethod)}} => ref value; } """; var verifier = CompileAndVerify(new[] { source, UnscopedRefAttributeDefinition }, expectedOutput: "12", verify: Verification.Fails); verifier.VerifyDiagnostics(); verifier.VerifyMethodBody("C.Value", $$""" { // Code size 17 (0x11) .maxstack 1 // sequence point: s1.S2{{csharp(firstIsMethod)}}.Value{{csharp(secondIsMethod)}} IL_0000: ldarg.0 IL_0001: ldflda "S1 C.s1" IL_0006: call "ref S2 S1.S2{{il(firstIsMethod)}}" IL_000b: call "ref int S2.Value{{il(secondIsMethod)}}" IL_0010: ret } """); static string csharp(bool method) => method ? "()" : ""; static string il(bool method) => method ? "()" : ".get"; } [Fact] public void UnscopedRefAttribute_NestedAccess_Properties_Invalid() { var source = """ using System.Diagnostics.CodeAnalysis; class C { private S1 s1; public ref int Value() => ref s1.S2.Value; } struct S1 { private S2 s2; public S2 S2 => s2; } struct S2 { private int value; [UnscopedRef] public ref int Value => ref value; } """; CreateCompilation(new[] { source, UnscopedRefAttributeDefinition }).VerifyDiagnostics( // 0.cs(6,35): error CS8156: An expression cannot be used in this context because it may not be passed or returned by reference // public ref int Value() => ref s1.S2.Value; Diagnostic(ErrorCode.ERR_RefReturnLvalueExpected, "s1.S2").WithLocation(6, 35), // 0.cs(11,16): warning CS0649: Field 'S1.s2' is never assigned to, and will always have its default value // private S2 s2; Diagnostic(ErrorCode.WRN_UnassignedInternalField, "s2").WithArguments("S1.s2", "").WithLocation(11, 16)); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/69997")] public void UnscopedRefAttribute_NestedAccess_Properties_Incomplete() { var source = """ using System.Diagnostics.CodeAnalysis; class C { private S1 s1; public ref int Value() => ref s1.S2.Value; } struct S1 { private S2 s2; public S2 S2 { } } struct S2 { private int value; [UnscopedRef] public ref int Value => ref value; } """; CreateCompilation(new[] { source, UnscopedRefAttributeDefinition }).VerifyDiagnostics( // 0.cs(6,35): error CS0154: The property or indexer 'S1.S2' cannot be used in this context because it lacks the get accessor // public ref int Value() => ref s1.S2.Value; Diagnostic(ErrorCode.ERR_PropertyLacksGet, "s1.S2").WithArguments("S1.S2").WithLocation(6, 35), // 0.cs(12,15): error CS0548: 'S1.S2': property or indexer must have at least one accessor // public S2 S2 { } Diagnostic(ErrorCode.ERR_PropertyWithNoAccessors, "S2").WithArguments("S1.S2").WithLocation(12, 15)); } [Theory, CombinatorialData] public void UnscopedRefAttribute_NestedAccess_MethodOrProperty_Readonly( [CombinatorialValues("", "()")] string op1, [CombinatorialValues("", "()")] string op2) { var source = $$""" using System.Diagnostics.CodeAnalysis; class C { private S1 s1; public ref int Value() => ref s1.S2{{op1}}.Value{{op2}}; } struct S1 { private readonly S2 s2; [UnscopedRef] public ref readonly S2 S2{{op1}} => ref s2; } struct S2 { private int value; [UnscopedRef] public ref int Value{{op2}} => ref value; } """; CreateCompilation(new[] { source, UnscopedRefAttributeDefinition }).VerifyDiagnostics( // 0.cs(6,35): error CS8156: An expression cannot be used in this context because it may not be passed or returned by reference // public ref int Value() => ref s1.S2.Value; Diagnostic(ErrorCode.ERR_RefReturnLvalueExpected, $"s1.S2{op1}").WithLocation(6, 35)); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/67626")] public void UnscopedRefAttribute_NestedAccess_Indexer() { var source = $$""" using System.Diagnostics.CodeAnalysis; var c = new C(); c.Value(0) = 12; System.Console.WriteLine(c.Value(0)); class C { private S1 s1; public ref int Value(int i) => ref s1[i].Value; } struct S1 { private S2 s2; [UnscopedRef] public ref S2 this[int i] => ref s2; } struct S2 { private int value; [UnscopedRef] public ref int Value => ref value; } """; var verifier = CompileAndVerify(new[] { source, UnscopedRefAttributeDefinition }, expectedOutput: "12", verify: Verification.Fails); verifier.VerifyDiagnostics(); verifier.VerifyMethodBody("C.Value", """ { // Code size 18 (0x12) .maxstack 2 // sequence point: s1[i].Value IL_0000: ldarg.0 IL_0001: ldflda "S1 C.s1" IL_0006: ldarg.1 IL_0007: call "ref S2 S1.this[int].get" IL_000c: call "ref int S2.Value.get" IL_0011: ret } """); } [Fact] public void UnscopedRefAttribute_NestedAccess_Indexer_Invalid() { var source = """ using System.Diagnostics.CodeAnalysis; class C { private S1 s1; public ref int Value(int i) => ref s1[i].Value; } struct S1 { private S2 s2; public S2 this[int i] => s2; } struct S2 { private int value; [UnscopedRef] public ref int Value => ref value; } """; CreateCompilation(new[] { source, UnscopedRefAttributeDefinition }).VerifyDiagnostics( // 0.cs(6,40): error CS8156: An expression cannot be used in this context because it may not be passed or returned by reference // public ref int Value(int i) => ref s1[i].Value; Diagnostic(ErrorCode.ERR_RefReturnLvalueExpected, "s1[i]").WithLocation(6, 40), // 0.cs(11,16): warning CS0649: Field 'S1.s2' is never assigned to, and will always have its default value // private S2 s2; Diagnostic(ErrorCode.WRN_UnassignedInternalField, "s2").WithArguments("S1.s2", "").WithLocation(11, 16)); } [Fact] public void UnscopedRefAttribute_NestedAccess_Indexer_Readonly() { var source = """ using System.Diagnostics.CodeAnalysis; class C { private S1 s1; public ref int Value(int i) => ref s1[i][i]; } struct S1 { private readonly S2 s2; [UnscopedRef] public ref readonly S2 this[int i] => ref s2; } struct S2 { private int value; [UnscopedRef] public ref int this[int i] => ref value; } """; CreateCompilation(new[] { source, UnscopedRefAttributeDefinition }).VerifyDiagnostics( // 0.cs(6,40): error CS8156: An expression cannot be used in this context because it may not be passed or returned by reference // public ref int Value(int i) => ref s1[i].Value; Diagnostic(ErrorCode.ERR_RefReturnLvalueExpected, "s1[i]").WithLocation(6, 40)); } [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.VerifyEmitDiagnostics(); } 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_UnrecognizedAttributeVersion, "A.F1").WithArguments("A.F1(out int)", "System.Runtime.CompilerServices.RefSafetyRulesAttribute", "11").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); // 'A.F1' not used => no error CreateCompilation("class C;", references: [refA]).VerifyEmitDiagnostics(); } [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_UnrecognizedAttributeVersion, "A.F1").WithArguments("A.F1(out int)", "System.Runtime.CompilerServices.RefSafetyRulesAttribute", "11").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); // 'A.F1' not used => no error CreateCompilation("class C;", references: [refA]).VerifyEmitDiagnostics(); } [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_UnrecognizedAttributeVersion, "A.F1").WithArguments("A.F1(out int)", "System.Runtime.CompilerServices.RefSafetyRulesAttribute", "11").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); // 'A.F1' not used => no error CreateCompilation("class C;", references: [refA]).VerifyEmitDiagnostics(); } /// <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(Feature.RunNullableAnalysis, "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(Feature.RunNullableAnalysis, "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,27): error CS8374: Cannot ref-assign 'F(stackalloc byte[1])' to '_f1' because 'F(stackalloc byte[1])' has a narrower escape scope than '_f1'. // public ref byte _f1 = ref F(stackalloc byte[1]); Diagnostic(ErrorCode.ERR_RefAssignNarrower, "ref F(stackalloc byte[1])").WithArguments("_f1", "F(stackalloc byte[1])").WithLocation(4, 27), // (5,36): error CS8374: Cannot ref-assign 'F(stackalloc byte[1])' to '_f2' because 'F(stackalloc byte[1])' has a narrower escape scope than '_f2'. // public ref readonly byte _f2 = ref F(stackalloc byte[1]); Diagnostic(ErrorCode.ERR_RefAssignNarrower, "ref F(stackalloc byte[1])").WithArguments("_f2", "F(stackalloc byte[1])").WithLocation(5, 36) ); } // 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 CS8374: Cannot ref-assign 'F(stackalloc byte[1])' to '_f1' because 'F(stackalloc byte[1])' has a narrower escape scope than '_f1'. // ref byte _f1 = F(stackalloc byte[1]); Diagnostic(ErrorCode.ERR_RefAssignNarrower, "F(stackalloc byte[1])").WithArguments("_f1", "F(stackalloc byte[1])").WithLocation(4, 20), // (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 CS8374: Cannot ref-assign 'F(stackalloc byte[1])' to '_f2' because 'F(stackalloc byte[1])' has a narrower escape scope than '_f2'. // ref readonly byte _f2 = F(stackalloc byte[1]); Diagnostic(ErrorCode.ERR_RefAssignNarrower, "F(stackalloc byte[1])").WithArguments("_f2", "F(stackalloc byte[1])").WithLocation(5, 29) ); } [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,33): error CS8374: Cannot ref-assign 'F(stackalloc int[1])' to '_s' because 'F(stackalloc int[1])' has a narrower escape scope than '_s'. // ref readonly Span<int> _s = ref F(stackalloc int[1]); Diagnostic(ErrorCode.ERR_RefAssignNarrower, "ref F(stackalloc int[1])").WithArguments("_s", "F(stackalloc int[1])").WithLocation(4, 33) ); } [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,20): error CS8374: Cannot ref-assign 'F<byte>(out var b1)' to '_f1' because 'F<byte>(out var b1)' has a narrower escape scope than '_f1'. // ref byte _f1 = ref F<byte>(out var b1); // 1 Diagnostic(ErrorCode.ERR_RefAssignNarrower, "ref F<byte>(out var b1)").WithArguments("_f1", "F<byte>(out var b1)").WithLocation(4, 20), // (5,29): error CS8374: Cannot ref-assign 'F<byte>(out var b2)' to '_f2' because 'F<byte>(out var b2)' has a narrower escape scope than '_f2'. // ref readonly byte _f2 = ref F<byte>(out var b2); // 2 Diagnostic(ErrorCode.ERR_RefAssignNarrower, "ref F<byte>(out var b2)").WithArguments("_f2", "F<byte>(out var b2)").WithLocation(5, 29) ); } [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 CS8350: This combination of arguments to 'Repro.GetReference3(out Repro.RefStruct)' is disallowed because it may expose variables referenced by parameter 'rs' outside of their declaration scope // GetReference3(out s1).RefField = ref value; // 3 Diagnostic(ErrorCode.ERR_CallArgMixing, "GetReference3(out s1)").WithArguments("Repro.GetReference3(out Repro.RefStruct)", "rs").WithLocation(10, 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), // (10,27): error CS8168: Cannot return local 's1' by reference because it is not a ref local // GetReference3(out s1).RefField = ref value; // 3 Diagnostic(ErrorCode.ERR_RefReturnLocal, "s1").WithArguments("s1").WithLocation(10, 27), // (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), // (14,9): error CS8350: This combination of arguments to 'Repro.GetReadonlyReference3(out Repro.RefStruct)' is disallowed because it may expose variables referenced by parameter 'rs' outside of their declaration scope // GetReadonlyReference3(out s1).RefField = ref value; // 6 Diagnostic(ErrorCode.ERR_CallArgMixing, "GetReadonlyReference3(out s1)").WithArguments("Repro.GetReadonlyReference3(out Repro.RefStruct)", "rs").WithLocation(14, 9), // (14,35): error CS8168: Cannot return local 's1' by reference because it is not a ref local // GetReadonlyReference3(out s1).RefField = ref value; // 6 Diagnostic(ErrorCode.ERR_RefReturnLocal, "s1").WithArguments("s1").WithLocation(14, 35)); } [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)); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/80745")] public void ConstructorInitializer_03() { // Verify that a ref to local declared in a constructor initializer cannot escape into 'this' var source = """ ref struct R { R(int x, ref int y) { } public R() : this(M(out int x), ref x) // 1, 2 { } public static int M(out int x) => x = 1; } """; var comp = CreateCompilation(source); comp.VerifyDiagnostics( // (4,16): error CS8350: This combination of arguments to 'R.R(int, ref int)' is disallowed because it may expose variables referenced by parameter 'y' outside of their declaration scope // public R() : this(M(out int x), ref x) // 1, 2 Diagnostic(ErrorCode.ERR_CallArgMixing, ": this(M(out int x), ref x)").WithArguments("R.R(int, ref int)", "y").WithLocation(4, 16), // (4,41): error CS8168: Cannot return local 'x' by reference because it is not a ref local // public R() : this(M(out int x), ref x) // 1, 2 Diagnostic(ErrorCode.ERR_RefReturnLocal, "x").WithArguments("x").WithLocation(4, 41)); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/80745")] public void ConstructorInitializer_04() { // Verify that a local in a constructor initializer is assignable to a scoped ref struct parameter var source = """ using System; struct R { R(int x, int y) { } public R(scoped Span<int> span) : this(M(out int x), (span = new Span<int>(ref x))[0]) { } public static int M(out int x) => x = 1; } """; var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70); comp.VerifyDiagnostics(); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/80745")] public void ConstructorInitializer_05() { // Verify that a local in a constructor initializer is not assignable to a ref struct parameter var source = """ using System; struct R { R(int x, int y) { } public R(Span<int> span) : this(M(out int x), (span = new Span<int>(ref x))[0]) { } public static int M(out int x) => x = 1; } """; var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70); comp.VerifyDiagnostics( // (6,59): error CS8347: Cannot use a result of 'Span<int>.Span(ref int)' in this context because it may expose variables referenced by parameter 'reference' outside of their declaration scope // public R(Span<int> span) : this(M(out int x), (span = new Span<int>(ref x))[0]) Diagnostic(ErrorCode.ERR_EscapeCall, "new Span<int>(ref x)").WithArguments("System.Span<int>.Span(ref int)", "reference").WithLocation(6, 59), // (6,77): error CS8168: Cannot return local 'x' by reference because it is not a ref local // public R(Span<int> span) : this(M(out int x), (span = new Span<int>(ref x))[0]) Diagnostic(ErrorCode.ERR_RefReturnLocal, "x").WithArguments("x").WithLocation(6, 77)); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/80745")] public void OutParamVsConstructor_01() { // Expect 'this' in a constructor to behave similarly to an 'out' parameter in an ordinary method with respect to ref safety. var source = """ ref struct R { private ref readonly int _i; private R(in int i) => _i = ref i; // ok void M1(out R r, in int i) => r = new R(in i); // ok } """; var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70); comp.VerifyDiagnostics(); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/80745")] public void OutParamVsConstructor_02() { var source = """ ref struct R { private ref readonly int _i; private R(in int i) => _i = ref i; public R() { int i = 1; this = new R(in i); // 1, 2 } void M1(out R r) { int i = 1; r = new R(in i); // 3, 4 } } """; var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70); comp.VerifyDiagnostics( // (9,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 i); // 1, 2 Diagnostic(ErrorCode.ERR_EscapeCall, "new R(in i)").WithArguments("R.R(in int)", "i").WithLocation(9, 16), // (9,25): error CS8168: Cannot return local 'i' by reference because it is not a ref local // this = new R(in i); // 1, 2 Diagnostic(ErrorCode.ERR_RefReturnLocal, "i").WithArguments("i").WithLocation(9, 25), // (15,13): 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 // r = new R(in i); // 3, 4 Diagnostic(ErrorCode.ERR_EscapeCall, "new R(in i)").WithArguments("R.R(in int)", "i").WithLocation(15, 13), // (15,22): error CS8168: Cannot return local 'i' by reference because it is not a ref local // r = new R(in i); // 3, 4 Diagnostic(ErrorCode.ERR_RefReturnLocal, "i").WithArguments("i").WithLocation(15, 22)); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/80745")] public void OutParamVsConstructor_03() { var source = """ ref struct R { private ref readonly int _i; private R(in int i) => _i = ref i; public R() { this = new R(1); // 1, 2 } void M1(out R r) => r = new R(1); // 3, 4 } """; var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70); comp.VerifyDiagnostics( // (8,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(1); // 1, 2 Diagnostic(ErrorCode.ERR_EscapeCall, "new R(1)").WithArguments("R.R(in int)", "i").WithLocation(8, 16), // (8,22): error CS8156: An expression cannot be used in this context because it may not be passed or returned by reference // this = new R(1); // 1, 2 Diagnostic(ErrorCode.ERR_RefReturnLvalueExpected, "1").WithLocation(8, 22), // (12,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 // => r = new R(1); // 3, 4 Diagnostic(ErrorCode.ERR_EscapeCall, "new R(1)").WithArguments("R.R(in int)", "i").WithLocation(12, 16), // (12,22): error CS8156: An expression cannot be used in this context because it may not be passed or returned by reference // => r = new R(1); // 3, 4 Diagnostic(ErrorCode.ERR_RefReturnLvalueExpected, "1").WithLocation(12, 22)); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/80745")] public void OutParamVsConstructor_04() { var source = """ ref struct R { private ref readonly int _i; private R(in int i) => _i = ref i; public R() { int i = 1; M1(out this, in i); // 1, 2 } void M1(out R r, in int i) => r = new R(in i); // ok void M2(out R r) { int i = 1; M1(out r, in i); // 3, 4 } } """; var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70); comp.VerifyDiagnostics( // (9,9): error CS8350: This combination of arguments to 'R.M1(out R, in int)' is disallowed because it may expose variables referenced by parameter 'i' outside of their declaration scope // M1(out this, in i); // 1, 2 Diagnostic(ErrorCode.ERR_CallArgMixing, "M1(out this, in i)").WithArguments("R.M1(out R, in int)", "i").WithLocation(9, 9), // (9,25): error CS8168: Cannot return local 'i' by reference because it is not a ref local // M1(out this, in i); // 1, 2 Diagnostic(ErrorCode.ERR_RefReturnLocal, "i").WithArguments("i").WithLocation(9, 25), // (18,9): error CS8350: This combination of arguments to 'R.M1(out R, in int)' is disallowed because it may expose variables referenced by parameter 'i' outside of their declaration scope // M1(out r, in i); // 3, 4 Diagnostic(ErrorCode.ERR_CallArgMixing, "M1(out r, in i)").WithArguments("R.M1(out R, in int)", "i").WithLocation(18, 9), // (18,22): error CS8168: Cannot return local 'i' by reference because it is not a ref local // M1(out r, in i); // 3, 4 Diagnostic(ErrorCode.ERR_RefReturnLocal, "i").WithArguments("i").WithLocation(18, 22)); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/80745")] public void OutParamVsConstructor_05() { var source = """ ref struct R { private ref readonly int _i; private R(in int i) => _i = ref i; void M1(out R r, in int i) => r = new R(in i); public R() => M1(out this, 1); // 1, 2 void M2(out R r) => M1(out r, 1); // 3, 4 } """; var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70); comp.VerifyDiagnostics( // (10,12): error CS8350: This combination of arguments to 'R.M1(out R, in int)' is disallowed because it may expose variables referenced by parameter 'i' outside of their declaration scope // => M1(out this, 1); // 1, 2 Diagnostic(ErrorCode.ERR_CallArgMixing, "M1(out this, 1)").WithArguments("R.M1(out R, in int)", "i").WithLocation(10, 12), // (10,25): error CS8156: An expression cannot be used in this context because it may not be passed or returned by reference // => M1(out this, 1); // 1, 2 Diagnostic(ErrorCode.ERR_RefReturnLvalueExpected, "1").WithLocation(10, 25), // (13,12): error CS8350: This combination of arguments to 'R.M1(out R, in int)' is disallowed because it may expose variables referenced by parameter 'i' outside of their declaration scope // => M1(out r, 1); // 3, 4 Diagnostic(ErrorCode.ERR_CallArgMixing, "M1(out r, 1)").WithArguments("R.M1(out R, in int)", "i").WithLocation(13, 12), // (13,22): error CS8156: An expression cannot be used in this context because it may not be passed or returned by reference // => M1(out r, 1); // 3, 4 Diagnostic(ErrorCode.ERR_RefReturnLvalueExpected, "1").WithLocation(13, 22)); } [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)); } [ConditionalFact(typeof(CoreClrOnly)), WorkItem("https://github.com/dotnet/roslyn/issues/69148")] public void RefField_Assignment_AutoDefault_01() { var verifier = CompileAndVerify(""" using System; try { new RS(); } catch (NullReferenceException) { Console.Write(1); } ref struct RS { ref int ri; public RS() => ri = 0; } """, options: TestOptions.DebugExe.WithSpecificDiagnosticOptions(ReportStructInitializationWarnings), verify: Verification.Skipped, targetFramework: TargetFramework.NetCoreApp, expectedOutput: "1"); verifier.VerifyDiagnostics( // (14,13): warning CS9265: Field 'RS.ri' is never ref-assigned to, and will always have its default value (null reference) // ref int ri; Diagnostic(ErrorCode.WRN_UnassignedInternalRefField, "ri").WithArguments("RS.ri").WithLocation(14, 13), // (15,20): warning CS9201: Ref field 'ri' should be ref-assigned before use. // public RS() => ri = 0; Diagnostic(ErrorCode.WRN_UseDefViolationRefField, "ri").WithArguments("ri").WithLocation(15, 20)); verifier.VerifyIL("RS..ctor", """ { // Code size 17 (0x11) .maxstack 2 IL_0000: ldarg.0 IL_0001: ldc.i4.0 IL_0002: conv.u IL_0003: stfld "ref int RS.ri" IL_0008: ldarg.0 IL_0009: ldfld "ref int RS.ri" IL_000e: ldc.i4.0 IL_000f: stind.i4 IL_0010: ret } """); } [ConditionalFact(typeof(CoreClrOnly)), WorkItem("https://github.com/dotnet/roslyn/issues/69148")] public void RefField_Assignment_AutoDefault_02() { var verifier = CompileAndVerify(""" using System; try { new RS(); } catch (NullReferenceException) { Console.Write(1); } ref struct RS { ref int ri; public RS() { int local = ri; } } """, options: TestOptions.DebugExe.WithSpecificDiagnosticOptions(ReportStructInitializationWarnings), verify: Verification.Skipped, targetFramework: TargetFramework.NetCoreApp, expectedOutput: "1"); verifier.VerifyDiagnostics( // (14,13): warning CS9265: Field 'RS.ri' is never ref-assigned to, and will always have its default value (null reference) // ref int ri; Diagnostic(ErrorCode.WRN_UnassignedInternalRefField, "ri").WithArguments("RS.ri").WithLocation(14, 13), // (15,12): warning CS9022: Control is returned to caller before field 'RS.ri' is explicitly assigned, causing a preceding implicit assignment of 'default'. // public RS() Diagnostic(ErrorCode.WRN_UnassignedThisSupportedVersion, "RS").WithArguments("RS.ri").WithLocation(15, 12), // (17,21): warning CS9201: Ref field 'ri' should be ref-assigned before use. // int local = ri; Diagnostic(ErrorCode.WRN_UseDefViolationRefField, "ri").WithArguments("ri").WithLocation(17, 21)); verifier.VerifyIL("RS..ctor", """ { // Code size 18 (0x12) .maxstack 2 .locals init (int V_0) //local IL_0000: nop IL_0001: ldarg.0 IL_0002: ldc.i4.0 IL_0003: conv.u IL_0004: stfld "ref int RS.ri" IL_0009: ldarg.0 IL_000a: ldfld "ref int RS.ri" IL_000f: ldind.i4 IL_0010: stloc.0 IL_0011: ret } """); } [ConditionalFact(typeof(CoreClrOnly)), WorkItem("https://github.com/dotnet/roslyn/issues/69148")] public void RefField_Assignment_AutoDefault_03() { var verifier = CompileAndVerify(""" using System; new RS(); Console.Write(1); try { new RS(ignored: true); } catch { Console.Write(2); } ref struct RS { ref int ri; public RS() { ref int local = ref ri; // 1 } public RS(bool ignored) { ref int local = ref ri; // 2 Console.Write(local); } } """, options: TestOptions.DebugExe.WithSpecificDiagnosticOptions(ReportStructInitializationWarnings), verify: Verification.Skipped, targetFramework: TargetFramework.NetCoreApp, expectedOutput: "12"); verifier.VerifyDiagnostics( // (17,13): warning CS9265: Field 'RS.ri' is never ref-assigned to, and will always have its default value (null reference) // ref int ri; Diagnostic(ErrorCode.WRN_UnassignedInternalRefField, "ri").WithArguments("RS.ri").WithLocation(17, 13), // (20,29): warning CS9201: Ref field 'ri' should be ref-assigned before use. // ref int local = ref ri; // 1 Diagnostic(ErrorCode.WRN_UseDefViolationRefField, "ri").WithArguments("ri").WithLocation(20, 29), // (25,29): warning CS9201: Ref field 'ri' should be ref-assigned before use. // ref int local = ref ri; // 2 Diagnostic(ErrorCode.WRN_UseDefViolationRefField, "ri").WithArguments("ri").WithLocation(25, 29)); verifier.VerifyIL("RS..ctor", """ { // Code size 17 (0x11) .maxstack 2 .locals init (int& V_0) //local IL_0000: nop IL_0001: ldarg.0 IL_0002: ldc.i4.0 IL_0003: conv.u IL_0004: stfld "ref int RS.ri" IL_0009: ldarg.0 IL_000a: ldfld "ref int RS.ri" IL_000f: stloc.0 IL_0010: ret } """); } [ConditionalFact(typeof(CoreClrOnly)), WorkItem("https://github.com/dotnet/roslyn/issues/69148")] public void RefField_Assignment_AutoDefault_04() { var verifier = CompileAndVerify(""" using System; var i = 1; var rs = new RS(ref i); i = 2; rs = new RS(ref i, ignored: true); ref struct RS { ref int ri; public RS(ref int ri) { this.ri = ref ri; Console.Write(this.ri); } public RS(ref int ri, bool ignored) { this = default(RS) with { ri = ref ri }; Console.Write(this.ri); } } """, options: TestOptions.DebugExe.WithSpecificDiagnosticOptions(ReportStructInitializationWarnings), verify: Verification.Skipped, targetFramework: TargetFramework.NetCoreApp, expectedOutput: "12"); verifier.VerifyDiagnostics(); } [ConditionalFact(typeof(CoreClrOnly)), WorkItem("https://github.com/dotnet/roslyn/issues/69148")] public void RefField_Assignment_AutoDefault_05() { var comp = CreateCompilation(""" ref struct RS { ref readonly int ri; public RS() => ri = 0; } """, targetFramework: TargetFramework.NetCoreApp); comp.VerifyDiagnostics( // (3,22): warning CS9265: Field 'RS.ri' is never ref-assigned to, and will always have its default value (null reference) // ref readonly int ri; Diagnostic(ErrorCode.WRN_UnassignedInternalRefField, "ri").WithArguments("RS.ri").WithLocation(3, 22), // (4,20): error CS8331: Cannot assign to field 'ri' or use it as the right hand side of a ref assignment because it is a readonly variable // public RS() => ri = 0; Diagnostic(ErrorCode.ERR_AssignReadonlyNotField, "ri").WithArguments("field", "ri").WithLocation(4, 20), // (4,20): warning CS9201: Ref field 'ri' should be ref-assigned before use. // public RS() => ri = 0; Diagnostic(ErrorCode.WRN_UseDefViolationRefField, "ri").WithArguments("ri").WithLocation(4, 20)); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/75035")] public void RefField_AsRefArgument_01() { var verifier = CompileAndVerify(""" ref struct S { public ref int F1; public static S GetS() => default; static void M(ref int x){} static void Test1() { M(ref GetS().F1); } } """, verify: Verification.Skipped, targetFramework: TargetFramework.NetCoreApp); verifier.VerifyDiagnostics( // (3,20): warning CS9265: Field 'S.F1' is never ref-assigned to, and will always have its default value (null reference) // public ref int F1; Diagnostic(ErrorCode.WRN_UnassignedInternalRefField, "F1").WithArguments("S.F1").WithLocation(3, 20)); verifier.VerifyIL("S.Test1", @" { // Code size 19 (0x13) .maxstack 1 .locals init (S V_0) IL_0000: call ""S S.GetS()"" IL_0005: stloc.0 IL_0006: ldloca.s V_0 IL_0008: ldfld ""ref int S.F1"" IL_000d: call ""void S.M(ref int)"" IL_0012: ret } "); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/75035")] public void RefField_AsRefArgument_02() { var comp = CreateCompilation(""" ref struct S { public ref readonly int F1; public static S GetS() => default; static void M(ref readonly int x){} static void Test1() { M(ref GetS().F1); } } """, targetFramework: TargetFramework.NetCoreApp); comp.VerifyDiagnostics( // (3,29): warning CS9265: Field 'S.F1' is never ref-assigned to, and will always have its default value (null reference) // public ref readonly int F1; Diagnostic(ErrorCode.WRN_UnassignedInternalRefField, "F1").WithArguments("S.F1").WithLocation(3, 29), // (11,15): error CS8329: Cannot use field 'F1' as a ref or out value because it is a readonly variable // M(ref GetS().F1); Diagnostic(ErrorCode.ERR_RefReadonlyNotField, "GetS().F1").WithArguments("field", "F1").WithLocation(11, 15) ); } [Fact] [WorkItem("https://github.com/dotnet/roslyn/issues/75035")] [WorkItem("https://github.com/dotnet/roslyn/issues/75082")] public void RefField_AsRefArgument_03() { var verifier = CompileAndVerify(""" ref struct S { public ref readonly int F1; public static S GetS() => default; static void M(ref readonly int x){} static void Test1() { M(in GetS().F1); } } """, verify: Verification.Skipped, targetFramework: TargetFramework.NetCoreApp); verifier.VerifyDiagnostics( // (3,29): warning CS9265: Field 'S.F1' is never ref-assigned to, and will always have its default value (null reference) // public ref readonly int F1; Diagnostic(ErrorCode.WRN_UnassignedInternalRefField, "F1").WithArguments("S.F1").WithLocation(3, 29)); verifier.VerifyIL("S.Test1", """ { // Code size 19 (0x13) .maxstack 1 .locals init (S V_0) IL_0000: call "S S.GetS()" IL_0005: stloc.0 IL_0006: ldloca.s V_0 IL_0008: ldfld "ref readonly int S.F1" IL_000d: call "void S.M(ref readonly int)" IL_0012: ret } """); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/75035")] public void RefField_AsRefArgument_04() { var comp = CreateCompilation(""" ref struct S { public ref readonly int F1; public static S GetS() => default; static void M(in int x){} static void Test1() { M(ref GetS().F1); } } """, targetFramework: TargetFramework.NetCoreApp); comp.VerifyDiagnostics( // (3,29): warning CS9265: Field 'S.F1' is never ref-assigned to, and will always have its default value (null reference) // public ref readonly int F1; Diagnostic(ErrorCode.WRN_UnassignedInternalRefField, "F1").WithArguments("S.F1").WithLocation(3, 29), // (11,15): error CS8329: Cannot use field 'F1' as a ref or out value because it is a readonly variable // M(ref GetS().F1); Diagnostic(ErrorCode.ERR_RefReadonlyNotField, "GetS().F1").WithArguments("field", "F1").WithLocation(11, 15) ); } [Fact] [WorkItem("https://github.com/dotnet/roslyn/issues/75035")] [WorkItem("https://github.com/dotnet/roslyn/issues/75082")] public void RefField_AsRefArgument_05() { var verifier = CompileAndVerify(""" ref struct S { public ref readonly int F1; public static S GetS() => default; static void M(in int x){} static void Test1() { M(in GetS().F1); } } """, verify: Verification.Skipped, targetFramework: TargetFramework.NetCoreApp); verifier.VerifyDiagnostics( // (3,29): warning CS9265: Field 'S.F1' is never ref-assigned to, and will always have its default value (null reference) // public ref readonly int F1; Diagnostic(ErrorCode.WRN_UnassignedInternalRefField, "F1").WithArguments("S.F1").WithLocation(3, 29)); verifier.VerifyIL("S.Test1", """ { // Code size 19 (0x13) .maxstack 1 .locals init (S V_0) IL_0000: call "S S.GetS()" IL_0005: stloc.0 IL_0006: ldloca.s V_0 IL_0008: ldfld "ref readonly int S.F1" IL_000d: call "void S.M(in int)" IL_0012: ret } """); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/75035")] public void RefField_AsRefArgument_06() { var verifier = CompileAndVerify(""" #pragma warning disable CS9265 // Field 'S.F1' is never ref-assigned to, and will always have its default value (null reference) ref struct S { public ref readonly int F1; public static S GetS() => default; static void M(in int x){} static void Test1() { M(GetS().F1); } } """, verify: Verification.Skipped, targetFramework: TargetFramework.NetCoreApp); verifier.VerifyDiagnostics(); verifier.VerifyIL("S.Test1", @" { // Code size 19 (0x13) .maxstack 1 .locals init (S V_0) IL_0000: call ""S S.GetS()"" IL_0005: stloc.0 IL_0006: ldloca.s V_0 IL_0008: ldfld ""ref readonly int S.F1"" IL_000d: call ""void S.M(in int)"" IL_0012: ret } "); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/75035")] public void RefField_AsRefArgument_07() { var verifier = CompileAndVerify(""" ref struct S { public readonly ref int F1; public static S GetS() => default; static void M(ref int x){} static void Test1() { M(ref GetS().F1); } } """, verify: Verification.Skipped, targetFramework: TargetFramework.NetCoreApp); verifier.VerifyDiagnostics( // (3,29): warning CS9265: Field 'S.F1' is never ref-assigned to, and will always have its default value (null reference) // public readonly ref int F1; Diagnostic(ErrorCode.WRN_UnassignedInternalRefField, "F1").WithArguments("S.F1").WithLocation(3, 29)); verifier.VerifyIL("S.Test1", @" { // Code size 19 (0x13) .maxstack 1 .locals init (S V_0) IL_0000: call ""S S.GetS()"" IL_0005: stloc.0 IL_0006: ldloca.s V_0 IL_0008: ldfld ""ref int S.F1"" IL_000d: call ""void S.M(ref int)"" IL_0012: ret } "); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/75035")] public void RefField_AsRefArgument_08() { var verifier = CompileAndVerify(""" ref struct S { public readonly ref int F1; public static S GetS() => default; static void M(ref readonly int x){} static void Test1() { M(ref GetS().F1); } } """, verify: Verification.Skipped, targetFramework: TargetFramework.NetCoreApp); verifier.VerifyDiagnostics( // (3,29): warning CS9265: Field 'S.F1' is never ref-assigned to, and will always have its default value (null reference) // public readonly ref int F1; Diagnostic(ErrorCode.WRN_UnassignedInternalRefField, "F1").WithArguments("S.F1").WithLocation(3, 29)); verifier.VerifyIL("S.Test1", @" { // Code size 19 (0x13) .maxstack 1 .locals init (S V_0) IL_0000: call ""S S.GetS()"" IL_0005: stloc.0 IL_0006: ldloca.s V_0 IL_0008: ldfld ""ref int S.F1"" IL_000d: call ""void S.M(ref readonly int)"" IL_0012: ret } "); } [Fact] [WorkItem("https://github.com/dotnet/roslyn/issues/75035")] [WorkItem("https://github.com/dotnet/roslyn/issues/75082")] public void RefField_AsRefArgument_09() { var verifier = CompileAndVerify(""" ref struct S { public readonly ref int F1; public static S GetS() => default; static void M(ref readonly int x){} static void Test1() { M(in GetS().F1); } } """, verify: Verification.Skipped, targetFramework: TargetFramework.NetCoreApp); verifier.VerifyDiagnostics( // (3,29): warning CS9265: Field 'S.F1' is never ref-assigned to, and will always have its default value (null reference) // public readonly ref int F1; Diagnostic(ErrorCode.WRN_UnassignedInternalRefField, "F1").WithArguments("S.F1").WithLocation(3, 29)); verifier.VerifyIL("S.Test1", """ { // Code size 19 (0x13) .maxstack 1 .locals init (S V_0) IL_0000: call "S S.GetS()" IL_0005: stloc.0 IL_0006: ldloca.s V_0 IL_0008: ldfld "ref int S.F1" IL_000d: call "void S.M(ref readonly int)" IL_0012: ret } """); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/75035")] public void RefField_AsRefArgument_10() { var verifier = CompileAndVerify(""" ref struct S { public readonly ref int F1; public static S GetS() => default; static void M(in int x){} static void Test1() { M(ref GetS().F1); } } """, verify: Verification.Skipped, targetFramework: TargetFramework.NetCoreApp); verifier.VerifyDiagnostics( // (3,29): warning CS9265: Field 'S.F1' is never ref-assigned to, and will always have its default value (null reference) // public readonly ref int F1; Diagnostic(ErrorCode.WRN_UnassignedInternalRefField, "F1").WithArguments("S.F1").WithLocation(3, 29), // (11,15): warning CS9191: The 'ref' modifier for argument 1 corresponding to 'in' parameter is equivalent to 'in'. Consider using 'in' instead. // M(ref GetS().F1); Diagnostic(ErrorCode.WRN_BadArgRef, "GetS().F1").WithArguments("1").WithLocation(11, 15) ); verifier.VerifyIL("S.Test1", @" { // Code size 19 (0x13) .maxstack 1 .locals init (S V_0) IL_0000: call ""S S.GetS()"" IL_0005: stloc.0 IL_0006: ldloca.s V_0 IL_0008: ldfld ""ref int S.F1"" IL_000d: call ""void S.M(in int)"" IL_0012: ret } "); } [Fact] [WorkItem("https://github.com/dotnet/roslyn/issues/75035")] [WorkItem("https://github.com/dotnet/roslyn/issues/75082")] public void RefField_AsRefArgument_11() { var verifier = CompileAndVerify(""" ref struct S { public readonly ref int F1; public static S GetS() => default; static void M(in int x){} static void Test1() { M(in GetS().F1); } } """, verify: Verification.Skipped, targetFramework: TargetFramework.NetCoreApp); verifier.VerifyDiagnostics( // (3,29): warning CS9265: Field 'S.F1' is never ref-assigned to, and will always have its default value (null reference) // public readonly ref int F1; Diagnostic(ErrorCode.WRN_UnassignedInternalRefField, "F1").WithArguments("S.F1").WithLocation(3, 29)); verifier.VerifyIL("S.Test1", """ { // Code size 19 (0x13) .maxstack 1 .locals init (S V_0) IL_0000: call "S S.GetS()" IL_0005: stloc.0 IL_0006: ldloca.s V_0 IL_0008: ldfld "ref int S.F1" IL_000d: call "void S.M(in int)" IL_0012: ret } """); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/75035")] public void RefField_AsRefArgument_12() { var verifier = CompileAndVerify(""" #pragma warning disable CS9265 // Field 'S.F1' is never ref-assigned to, and will always have its default value (null reference) ref struct S { public readonly ref int F1; public static S GetS() => default; static void M(in int x){} static void Test1() { M(GetS().F1); } } """, verify: Verification.Skipped, targetFramework: TargetFramework.NetCoreApp); verifier.VerifyDiagnostics(); verifier.VerifyIL("S.Test1", @" { // Code size 19 (0x13) .maxstack 1 .locals init (S V_0) IL_0000: call ""S S.GetS()"" IL_0005: stloc.0 IL_0006: ldloca.s V_0 IL_0008: ldfld ""ref int S.F1"" IL_000d: call ""void S.M(in int)"" IL_0012: ret } "); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/75082")] public void ThroughValue_RefOfRef() { var comp = CreateCompilation(""" ref struct R { public ref int F; public static R GetValue() => default; static void M(ref readonly int x) { } static void Test() { M(ref GetValue().F); } } """, targetFramework: TargetFramework.NetCoreApp); comp.VerifyDiagnostics( // (3,20): warning CS9265: Field 'R.F' is never ref-assigned to, and will always have its default value (null reference) // public ref int F; Diagnostic(ErrorCode.WRN_UnassignedInternalRefField, "F").WithArguments("R.F").WithLocation(3, 20)); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/75082")] public void ThroughValue_InOfRef() { var comp = CreateCompilation(""" ref struct R { public ref int F; public static R GetValue() => default; static void M(ref readonly int x) { } static void Test() { M(in GetValue().F); } } """, targetFramework: TargetFramework.NetCoreApp); comp.VerifyDiagnostics( // (3,20): warning CS9265: Field 'R.F' is never ref-assigned to, and will always have its default value (null reference) // public ref int F; Diagnostic(ErrorCode.WRN_UnassignedInternalRefField, "F").WithArguments("R.F").WithLocation(3, 20)); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/75082")] public void ThroughValue_InOfRef_Nested() { var comp = CreateCompilation(""" ref struct R { public ref int F; public R GetR() => default; public static R GetValue() => default; static void M(ref readonly int x) { } static void Test() { M(in GetValue().GetR().F); } } """, targetFramework: TargetFramework.NetCoreApp); comp.VerifyDiagnostics( // (3,20): warning CS9265: Field 'R.F' is never ref-assigned to, and will always have its default value (null reference) // public ref int F; Diagnostic(ErrorCode.WRN_UnassignedInternalRefField, "F").WithArguments("R.F").WithLocation(3, 20)); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/75082")] public void ThroughValue_OutOfRef() { var comp = CreateCompilation(""" ref struct R { public ref int F; public static R GetValue() => default; static void M(out int x) => throw null; static void Test() { M(out GetValue().F); } } """, targetFramework: TargetFramework.NetCoreApp); comp.VerifyDiagnostics( // (3,20): warning CS9265: Field 'R.F' is never ref-assigned to, and will always have its default value (null reference) // public ref int F; Diagnostic(ErrorCode.WRN_UnassignedInternalRefField, "F").WithArguments("R.F").WithLocation(3, 20)); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/75082")] public void ThroughValue_ValueOfRef_ToRefReadonly() { var comp = CreateCompilation(""" ref struct R { public ref int F; public static R GetValue() => default; static void M(ref readonly int x) { } static void Test() { M(GetValue().F); } } """, targetFramework: TargetFramework.NetCoreApp); comp.VerifyDiagnostics( // (3,20): warning CS9265: Field 'R.F' is never ref-assigned to, and will always have its default value (null reference) // public ref int F; Diagnostic(ErrorCode.WRN_UnassignedInternalRefField, "F").WithArguments("R.F").WithLocation(3, 20), // (11,11): warning CS9192: Argument 1 should be passed with 'ref' or 'in' keyword // M(GetValue().F); Diagnostic(ErrorCode.WRN_ArgExpectedRefOrIn, "GetValue().F").WithArguments("1").WithLocation(11, 11)); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/75082")] public void ThroughValue_ValueOfRef_ToIn() { var comp = CreateCompilation(""" ref struct R { public ref int F; public static R GetValue() => default; static void M(in int x) { } static void Test() { M(GetValue().F); } } """, targetFramework: TargetFramework.NetCoreApp); comp.VerifyDiagnostics( // (3,20): warning CS9265: Field 'R.F' is never ref-assigned to, and will always have its default value (null reference) // public ref int F; Diagnostic(ErrorCode.WRN_UnassignedInternalRefField, "F").WithArguments("R.F").WithLocation(3, 20)); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/75082")] public void ThroughValue_ValueOfRef_ToRef() { var comp = CreateCompilation(""" ref struct R { public ref int F; public static R GetValue() => default; static void M(ref int x) { } static void Test() { M(GetValue().F); } } """, targetFramework: TargetFramework.NetCoreApp); comp.VerifyDiagnostics( // (3,20): warning CS9265: Field 'R.F' is never ref-assigned to, and will always have its default value (null reference) // public ref int F; Diagnostic(ErrorCode.WRN_UnassignedInternalRefField, "F").WithArguments("R.F").WithLocation(3, 20), // (11,11): error CS1620: Argument 1 must be passed with the 'ref' keyword // M(GetValue().F); Diagnostic(ErrorCode.ERR_BadArgRef, "GetValue().F").WithArguments("1", "ref").WithLocation(11, 11)); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/75082")] public void ThroughValue_RefOfRefReadonly() { var comp = CreateCompilation(""" ref struct R { public ref readonly int F; public static R GetValue() => default; static void M(ref readonly int x) { } static void Test() { M(ref GetValue().F); } } """, targetFramework: TargetFramework.NetCoreApp); comp.VerifyDiagnostics( // (3,29): warning CS9265: Field 'R.F' is never ref-assigned to, and will always have its default value (null reference) // public ref readonly int F; Diagnostic(ErrorCode.WRN_UnassignedInternalRefField, "F").WithArguments("R.F").WithLocation(3, 29), // (11,15): error CS8329: Cannot use field 'F' as a ref or out value because it is a readonly variable // M(ref GetValue().F); Diagnostic(ErrorCode.ERR_RefReadonlyNotField, "GetValue().F").WithArguments("field", "F").WithLocation(11, 15)); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/75082")] public void ThroughValue_InOfRefReadonly() { var comp = CreateCompilation(""" ref struct R { public ref readonly int F; public static R GetValue() => default; static void M(ref readonly int x) { } static void Test() { M(in GetValue().F); } } """, targetFramework: TargetFramework.NetCoreApp); comp.VerifyDiagnostics( // (3,29): warning CS9265: Field 'R.F' is never ref-assigned to, and will always have its default value (null reference) // public ref readonly int F; Diagnostic(ErrorCode.WRN_UnassignedInternalRefField, "F").WithArguments("R.F").WithLocation(3, 29)); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/75082")] public void ThroughValue_OutOfRefReadonly() { var comp = CreateCompilation(""" ref struct R { public ref readonly int F; public static R GetValue() => default; static void M(out int x) => throw null; static void Test() { M(out GetValue().F); } } """, targetFramework: TargetFramework.NetCoreApp); comp.VerifyDiagnostics( // (3,29): warning CS9265: Field 'R.F' is never ref-assigned to, and will always have its default value (null reference) // public ref readonly int F; Diagnostic(ErrorCode.WRN_UnassignedInternalRefField, "F").WithArguments("R.F").WithLocation(3, 29), // (11,15): error CS8329: Cannot use field 'F' as a ref or out value because it is a readonly variable // M(out GetValue().F); Diagnostic(ErrorCode.ERR_RefReadonlyNotField, "GetValue().F").WithArguments("field", "F").WithLocation(11, 15)); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/75082")] public void ThroughValue_ValueOfRefReadonly_ToRefReadonly() { var comp = CreateCompilation(""" ref struct R { public ref readonly int F; public static R GetValue() => default; static void M(ref readonly int x) { } static void Test() { M(GetValue().F); } } """, targetFramework: TargetFramework.NetCoreApp); comp.VerifyDiagnostics( // (3,29): warning CS9265: Field 'R.F' is never ref-assigned to, and will always have its default value (null reference) // public ref readonly int F; Diagnostic(ErrorCode.WRN_UnassignedInternalRefField, "F").WithArguments("R.F").WithLocation(3, 29), // (11,11): warning CS9195: Argument 1 should be passed with the 'in' keyword // M(GetValue().F); Diagnostic(ErrorCode.WRN_ArgExpectedIn, "GetValue().F").WithArguments("1").WithLocation(11, 11)); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/75082")] public void ThroughValue_ValueOfRefReadonly_ToIn() { var comp = CreateCompilation(""" ref struct R { public ref readonly int F; public static R GetValue() => default; static void M(in int x) { } static void Test() { M(GetValue().F); } } """, targetFramework: TargetFramework.NetCoreApp); comp.VerifyDiagnostics( // (3,29): warning CS9265: Field 'R.F' is never ref-assigned to, and will always have its default value (null reference) // public ref readonly int F; Diagnostic(ErrorCode.WRN_UnassignedInternalRefField, "F").WithArguments("R.F").WithLocation(3, 29)); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/75082")] public void ThroughValue_ValueOfRefReadonly_ToRef() { var comp = CreateCompilation(""" ref struct R { public ref readonly int F; public static R GetValue() => default; static void M(ref int x) { } static void Test() { M(GetValue().F); } } """, targetFramework: TargetFramework.NetCoreApp); comp.VerifyDiagnostics( // (3,29): warning CS9265: Field 'R.F' is never ref-assigned to, and will always have its default value (null reference) // public ref readonly int F; Diagnostic(ErrorCode.WRN_UnassignedInternalRefField, "F").WithArguments("R.F").WithLocation(3, 29), // (11,11): error CS1620: Argument 1 must be passed with the 'ref' keyword // M(GetValue().F); Diagnostic(ErrorCode.ERR_BadArgRef, "GetValue().F").WithArguments("1", "ref").WithLocation(11, 11)); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/80244")] public void Repro_80244_NetCoreApp() { var comp = CreateCompilation(""" using System; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; ref struct SpanReader { long _spanEndStreamOffset; ReadOnlySpan<byte> _buffer; public SpanReader(ReadOnlySpan<byte> buffer, long spanStartStreamOffset) { _buffer = buffer; _spanEndStreamOffset = spanStartStreamOffset + buffer.Length; } public ref readonly T ReadRef<T>() where T : struct { if (_buffer.Length >= Unsafe.SizeOf<T>()) { ref readonly T ret = ref MemoryMarshal.Cast<byte, T>(_buffer)[0]; _buffer = _buffer.Slice(Unsafe.SizeOf<T>()); return ref ret; } else { throw new Exception(); } } } """, targetFramework: TargetFramework.NetCoreApp, parseOptions: TestOptions.Regular14); comp.VerifyEmitDiagnostics(); } [Theory, WorkItem("https://github.com/dotnet/roslyn/issues/80244")] [InlineData(LanguageVersion.CSharp8), InlineData(LanguageVersion.CSharp14)] public void Repro_80244_NetStandard(LanguageVersion consumerLanguageVersion) { var spanCompilation = CreateCompilation(TestSources.Span, options: TestOptions.UnsafeReleaseDll, parseOptions: TestOptions.Regular8); var spanReference = spanCompilation.EmitToImageReference(); var source0 = """ namespace System.Runtime.CompilerServices { public static class Unsafe { public static int SizeOf<T>() => throw null!; } } namespace System.Runtime.InteropServices { public static class MemoryMarshal { public static ReadOnlySpan<TTo> Cast<TFrom, TTo>(ReadOnlySpan<TFrom> span) where TFrom : struct => throw null!; } } """; var source1 = """ using System; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; ref struct SpanReader { long _spanEndStreamOffset; ReadOnlySpan<byte> _buffer; public SpanReader(ReadOnlySpan<byte> buffer, long spanStartStreamOffset) { _buffer = buffer; _spanEndStreamOffset = spanStartStreamOffset + buffer.Length; } public ref readonly T ReadRef<T>() where T : struct { if (_buffer.Length >= Unsafe.SizeOf<T>()) { ref readonly T ret = ref MemoryMarshal.Cast<byte, T>(_buffer)[0]; _buffer = _buffer.Slice(Unsafe.SizeOf<T>()); return ref ret; } else { throw new Exception(); } } } """; var comp = CreateCompilation([source0, source1], references: [spanReference], parseOptions: TestOptions.Regular.WithLanguageVersion(consumerLanguageVersion), targetFramework: TargetFramework.NetStandard20); comp.VerifyEmitDiagnostics(); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/80244")] public void Repro_80244_Simple() { var source0 = """ public ref struct RS { public ref byte this[int i] => throw null!; } """; var reference = CreateCompilation(source0, parseOptions: TestOptions.Regular8).EmitToImageReference(); var source1 = """ class Program { static ref byte M1(RS rs) { ref byte ret = ref rs[1]; return ref ret; } static ref byte M2(RS rs) { return ref rs[1]; } } """; var comp = CreateCompilation(source1, references: [reference], parseOptions: TestOptions.Regular8); comp.VerifyEmitDiagnostics(); } } }