/
githubmirror
/
roslyn
Обзор
Документация
Войти
/
githubmirror
/
roslyn
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
src/Compilers/CSharp/Test/Semantic/Semantics/SpanStackSafetyTests.cs
2 855 строк
102 KB
GameMicrowave
Fix: LINQ implicit anonymous type property allows stack-only type, causing runtime TypeLoadException (#84485)
29 июл 2026, 20:20
Не верифицирован
29 июл 2026, 20:20
58d28cd
Код
Авторство
О чём код?
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. #nullable disable using System.Collections.Generic; using Microsoft.CodeAnalysis.CSharp.Test.Utilities; using Microsoft.CodeAnalysis.Test.Utilities; using Roslyn.Test.Utilities; using Xunit; namespace Microsoft.CodeAnalysis.CSharp.UnitTests { /// <summary> /// this place is dedicated to binding related error tests /// </summary> [CompilerTrait(CompilerFeature.ReadOnlyReferences)] public class SpanStackSafetyTests : CompilingTestBase { [Fact] public void SpanAssignmentExpression() { var comp = CreateCompilationWithMscorlibAndSpan(@" using System; class C { void M() { Span<int> s1 = stackalloc int[1]; Span<int> s2 = new Span<int>(); s2 = (s2 = new Span<int>()); s2 = (s1 = s2); } }"); comp.VerifyDiagnostics(); } [Fact] public void SpanToSpanSwitch() { var comp = CreateCompilationWithMscorlibAndSpan(@" using System; class C { void M(Span<string> s) { switch (s) { case Span<string> span: break; } } }"); comp.VerifyDiagnostics(); } [Fact] public void SpanToObjectPatternSwitch() { var comp = CreateCompilationWithMscorlibAndSpan(@" using System; class C { void M(object o) { switch (o) { case Span<int> span: break; default: break; } } }"); comp.VerifyDiagnostics( // (10,18): error CS8121: An expression of type 'object' cannot be handled by a pattern of type 'Span<int>'. // case Span<int> span: Diagnostic(ErrorCode.ERR_PatternWrongType, "Span<int>").WithArguments("object", "System.Span<int>").WithLocation(10, 18) ); } [Fact] public void SpanToGenericPatternSwitch() { var comp = CreateCompilationWithMscorlibAndSpan(@" using System; class C { void M<T>(T t) { switch (t) { case Span<int> span: break; default: break; } } }"); comp.VerifyDiagnostics( // (9,18): error CS8121: An expression of type 'T' cannot be handled by a pattern of type 'Span<int>'. // case Span<int> span: Diagnostic(ErrorCode.ERR_PatternWrongType, "Span<int>").WithArguments("T", "System.Span<int>").WithLocation(9, 18) ); } [Fact] public void SpanToGenericPatternSwitch2() { var comp = CreateCompilationWithMscorlibAndSpan(@" using System; class C { void M<T>(T t) where T : struct { switch (t) { case Span<int> span: break; default: break; } } }"); comp.VerifyDiagnostics( // (9,18): error CS8121: An expression of type 'T' cannot be handled by a pattern of type 'Span<int>'. // case Span<int> span: Diagnostic(ErrorCode.ERR_PatternWrongType, "Span<int>").WithArguments("T", "System.Span<int>").WithLocation(9, 18) ); } [Fact] public void ObjectToSpanPatternSwitch() { var comp = CreateCompilationWithMscorlibAndSpan(@" using System; class C { void M(Span<string> s) { switch (s) { case Span<object> span: break; case object o: break; } } }"); comp.VerifyDiagnostics( // (9,18): error CS8121: An expression of type 'Span<string>' cannot be handled by a pattern of type 'Span<object>'. // case Span<object> span: Diagnostic(ErrorCode.ERR_PatternWrongType, "Span<object>").WithArguments("System.Span<string>", "System.Span<object>").WithLocation(9, 18), // (11,18): error CS8121: An expression of type 'Span<string>' cannot be handled by a pattern of type 'object'. // case object o: Diagnostic(ErrorCode.ERR_PatternWrongType, "object").WithArguments("System.Span<string>", "object").WithLocation(11, 18) ); } [Fact] public void GenericToSpanPatternSwitch() { var comp = CreateCompilationWithMscorlibAndSpan(@" using System; class C { void M<T>(Span<string> s) { switch (s) { case T t: break; } } }"); comp.VerifyDiagnostics( // (9,18): error CS8121: An expression of type 'Span<string>' cannot be handled by a pattern of type 'T'. // case T t: Diagnostic(ErrorCode.ERR_PatternWrongType, "T").WithArguments("System.Span<string>", "T").WithLocation(9, 18) ); } [Fact] public void GenericToSpanPatternSwitch2() { var comp = CreateCompilationWithMscorlibAndSpan(@" using System; class C { void M<T>(Span<string> s) where T : struct { switch (s) { case T t: break; } } }"); comp.VerifyDiagnostics( // (9,18): error CS8121: An expression of type 'Span<string>' cannot be handled by a pattern of type 'T'. // case T t: Diagnostic(ErrorCode.ERR_PatternWrongType, "T").WithArguments("System.Span<string>", "T").WithLocation(9, 18) ); } [Fact] public void SpanToSpanIsExpr() { var comp = CreateCompilationWithMscorlibAndSpan(@" using System; class C { bool M(Span<string> s) => s is Span<string> && s is Span<string> span; }"); comp.VerifyDiagnostics( // (5,31): warning CS0183: The given expression is always of the provided ('Span<string>') type // bool M(Span<string> s) => s is Span<string> && s is Span<string> span; Diagnostic(ErrorCode.WRN_IsAlwaysTrue, "s is Span<string>").WithArguments("System.Span<string>").WithLocation(5, 31)); } [Fact] public void ObjectToSpanIsExpr() { var comp = CreateCompilationWithMscorlibAndSpan(@" using System; class C { void M(object o) { if (o is Span<int>) { } if (o is Span<int> s) { } } }"); comp.VerifyDiagnostics( // (7,13): warning CS0184: The given expression is never of the provided ('Span<int>') type // if (o is Span<int>) Diagnostic(ErrorCode.WRN_IsAlwaysFalse, "o is Span<int>").WithArguments("System.Span<int>").WithLocation(7, 13), // (9,18): error CS8121: An expression of type 'object' cannot be handled by a pattern of type 'Span<int>'. // if (o is Span<int> s) Diagnostic(ErrorCode.ERR_PatternWrongType, "Span<int>").WithArguments("object", "System.Span<int>").WithLocation(9, 18)); } [Fact] public void GenericToSpanIsExpr() { var comp = CreateCompilationWithMscorlibAndSpan(@" using System; class C { void M<T>(T t) { if (t is Span<int>) { } if (t is Span<int> s) { } } }"); comp.VerifyDiagnostics( // (7,13): warning CS0184: The given expression is never of the provided ('Span<int>') type // if (t is Span<int>) Diagnostic(ErrorCode.WRN_IsAlwaysFalse, "t is Span<int>").WithArguments("System.Span<int>").WithLocation(7, 13), // (9,18): error CS8121: An expression of type 'T' cannot be handled by a pattern of type 'Span<int>'. // if (t is Span<int> s) Diagnostic(ErrorCode.ERR_PatternWrongType, "Span<int>").WithArguments("T", "System.Span<int>").WithLocation(9, 18)); } [Fact] public void SpanToObjectIsExpr() { var comp = CreateCompilationWithMscorlibAndSpan(@" using System; class C { void M(Span<int> s) { if (s is object) { } if (s is object o) { } } }"); comp.VerifyDiagnostics( // (7,13): warning CS0184: The given expression is never of the provided ('object') type // if (s is object) { } Diagnostic(ErrorCode.WRN_IsAlwaysFalse, "s is object").WithArguments("object").WithLocation(7, 13), // (8,18): error CS8121: An expression of type 'Span<int>' cannot be handled by a pattern of type 'object'. // if (s is object o) { } Diagnostic(ErrorCode.ERR_PatternWrongType, "object").WithArguments("System.Span<int>", "object").WithLocation(8, 18)); } [Fact] public void SpanToGenericIsExpr() { var comp = CreateCompilationWithMscorlibAndSpan(@" using System; class C { void M<T>(Span<int> s) { if (s is T) { } if (s is T t) { } } }"); comp.VerifyDiagnostics( // (7,13): warning CS0184: The given expression is never of the provided ('T') type // if (s is T) { } Diagnostic(ErrorCode.WRN_IsAlwaysFalse, "s is T").WithArguments("T").WithLocation(7, 13), // (8,18): error CS8121: An expression of type 'Span<int>' cannot be handled by a pattern of type 'T'. // if (s is T t) { } Diagnostic(ErrorCode.ERR_PatternWrongType, "T").WithArguments("System.Span<int>", "T").WithLocation(8, 18)); } [Fact] public void SpanToGenericIsExpr2() { var comp = CreateCompilationWithMscorlibAndSpan(@" using System; class C { void M<T>(Span<int> s) where T : struct { if (s is T) { } if (s is T t) { } } }"); comp.VerifyDiagnostics( // (7,13): warning CS0184: The given expression is never of the provided ('T') type // if (s is T) { } Diagnostic(ErrorCode.WRN_IsAlwaysFalse, "s is T").WithArguments("T").WithLocation(7, 13), // (8,18): error CS8121: An expression of type 'Span<int>' cannot be handled by a pattern of type 'T'. // if (s is T t) { } Diagnostic(ErrorCode.ERR_PatternWrongType, "T").WithArguments("System.Span<int>", "T").WithLocation(8, 18)); } [Fact] public void TrivialBoxing() { var text = @" using System; class Program { static void Main() { object x = new Span<int>(); object y = new ReadOnlySpan<byte>(); object z = new SpanLike<int>(); } } "; CSharpCompilation comp = CreateCompilationWithMscorlibAndSpan(text); comp.VerifyDiagnostics( // (8,20): error CS0029: Cannot implicitly convert type 'System.Span<int>' to 'object' // object x = new Span<int>(); Diagnostic(ErrorCode.ERR_NoImplicitConv, "new Span<int>()").WithArguments("System.Span<int>", "object").WithLocation(8, 20), // (9,20): error CS0029: Cannot implicitly convert type 'System.ReadOnlySpan<byte>' to 'object' // object y = new ReadOnlySpan<byte>(); Diagnostic(ErrorCode.ERR_NoImplicitConv, "new ReadOnlySpan<byte>()").WithArguments("System.ReadOnlySpan<byte>", "object").WithLocation(9, 20), // (10,20): error CS0029: Cannot implicitly convert type 'System.SpanLike<int>' to 'object' // object z = new SpanLike<int>(); Diagnostic(ErrorCode.ERR_NoImplicitConv, "new SpanLike<int>()").WithArguments("System.SpanLike<int>", "object") ); comp = CreateCompilationWithMscorlibAndSpanSrc(text); comp.VerifyDiagnostics( // (8,20): error CS0029: Cannot implicitly convert type 'System.Span<int>' to 'object' // object x = new Span<int>(); Diagnostic(ErrorCode.ERR_NoImplicitConv, "new Span<int>()").WithArguments("System.Span<int>", "object").WithLocation(8, 20), // (9,20): error CS0029: Cannot implicitly convert type 'System.ReadOnlySpan<byte>' to 'object' // object y = new ReadOnlySpan<byte>(); Diagnostic(ErrorCode.ERR_NoImplicitConv, "new ReadOnlySpan<byte>()").WithArguments("System.ReadOnlySpan<byte>", "object").WithLocation(9, 20), // (10,20): error CS0029: Cannot implicitly convert type 'System.SpanLike<int>' to 'object' // object z = new SpanLike<int>(); Diagnostic(ErrorCode.ERR_NoImplicitConv, "new SpanLike<int>()").WithArguments("System.SpanLike<int>", "object") ); } [Fact] public void LambdaCapturing() { var text = @" using System; class Program { // this should be ok public delegate Span<T> D1<T>(Span<T> arg); static void Main() { var x = new Span<int>(); D1<int> d = (t)=>t; x = d(x); // error due to capture Func<int> f = () => x[1]; } } "; CSharpCompilation comp = CreateCompilationWithMscorlibAndSpan(text); comp.VerifyDiagnostics( // (17,29): error CS8175: Cannot use ref local 'x' inside an anonymous method, lambda expression, or query expression // Func<int> f = () => x[1]; Diagnostic(ErrorCode.ERR_AnonDelegateCantUseLocal, "x").WithArguments("x").WithLocation(17, 29) ); } [Fact] public void GenericArgsAndConstraints() { var text = @" using System; class Program { static void Main() { var x = new Span<int>(); Func<Span<int>> d = ()=>x; } class C1<T> where T: Span<int> { } } "; CSharpCompilation comp = CreateCompilationWithMscorlibAndSpan(text); comp.VerifyDiagnostics( // (13,26): error CS0701: 'Span<int>' is not a valid constraint. A type used as a constraint must be an interface, a non-sealed class or a type parameter. // class C1<T> where T: Span<int> Diagnostic(ErrorCode.ERR_BadBoundType, "Span<int>").WithArguments("System.Span<int>").WithLocation(13, 26), // (10,14): 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 'TResult' in the generic type or method 'Func<TResult>' // Func<Span<int>> d = ()=>x; Diagnostic(ErrorCode.ERR_NotRefStructConstraintNotSatisfied, "Span<int>").WithArguments("System.Func<TResult>", "TResult", "System.Span<int>").WithLocation(10, 14), // (10,33): error CS8175: Cannot use ref local 'x' inside an anonymous method, lambda expression, or query expression // Func<Span<int>> d = ()=>x; Diagnostic(ErrorCode.ERR_AnonDelegateCantUseLocal, "x").WithArguments("x").WithLocation(10, 33) ); } [Fact] public void Arrays() { var text = @" using System; class Program { static void Main() { var x = new Span<int>[1]; var y = new SpanLike<int>[1,2]; } } "; CSharpCompilation comp = CreateCompilationWithMscorlibAndSpan(text); comp.VerifyDiagnostics( // (8,21): error CS0611: Array elements cannot be of type 'Span<int>' // var x = new Span<int>[1]; Diagnostic(ErrorCode.ERR_ArrayElementCantBeRefAny, "Span<int>").WithArguments("System.Span<int>"), // (10,21): error CS0611: Array elements cannot be of type 'SpanLike<int>' // var y = new SpanLike<int>[1,2]; Diagnostic(ErrorCode.ERR_ArrayElementCantBeRefAny, "SpanLike<int>").WithArguments("System.SpanLike<int>").WithLocation(10, 21) ); } [Fact] public void ByrefParam() { var text = @"using System; class Program { static void Main() { } // OK static void M1(scoped ref Span<string> ss) { } // OK static void M2(out SpanLike<string> ss) { ss = default; } // OK static void M3(scoped in Span<string> ss) { } // OK static void M3l(scoped in SpanLike<string> ss) { } // OK static ref Span<string> M4(ref Span<string> ss) { return ref ss; } // OK static ref readonly Span<string> M5(ref Span<string> ss) => ref ss; // Not OK // TypedReference baseline static ref TypedReference M1(ref TypedReference ss) => ref ss; } "; var comp = CreateCompilationWithMscorlibAndSpan(new[] { text, UnscopedRefAttributeDefinition }, parseOptions: TestOptions.Regular10); comp.VerifyDiagnostics( // (10,20): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater. // static void M1(scoped ref Span<string> ss) Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "scoped").WithArguments("ref fields", "11.0").WithLocation(10, 20), // (38,34): error CS1601: Cannot make reference to variable of type 'TypedReference' // static ref TypedReference M1(ref TypedReference ss) => ref ss; Diagnostic(ErrorCode.ERR_MethodArgCantBeRefAny, "ref TypedReference ss").WithArguments("System.TypedReference").WithLocation(38, 34), // (38,12): error CS1599: The return type of a method, delegate, or function pointer cannot be 'TypedReference' // static ref TypedReference M1(ref TypedReference ss) => ref ss; Diagnostic(ErrorCode.ERR_MethodReturnCantBeRefAny, "ref TypedReference").WithArguments("System.TypedReference").WithLocation(38, 12), // (21,20): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater. // static void M3(scoped in Span<string> ss) Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "scoped").WithArguments("ref fields", "11.0").WithLocation(21, 20), // (26,21): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater. // static void M3l(scoped in SpanLike<string> ss) Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "scoped").WithArguments("ref fields", "11.0").WithLocation(26, 21) ); comp = CreateCompilationWithMscorlibAndSpan(new[] { text, UnscopedRefAttributeDefinition }); comp.VerifyDiagnostics( // (38,34): error CS1601: Cannot make reference to variable of type 'TypedReference' // static ref TypedReference M1(ref TypedReference ss) => ref ss; Diagnostic(ErrorCode.ERR_MethodArgCantBeRefAny, "ref TypedReference ss").WithArguments("System.TypedReference").WithLocation(38, 34), // (38,12): error CS1599: The return type of a method, delegate, or function pointer cannot be 'TypedReference' // static ref TypedReference M1(ref TypedReference ss) => ref ss; Diagnostic(ErrorCode.ERR_MethodReturnCantBeRefAny, "ref TypedReference").WithArguments("System.TypedReference").WithLocation(38, 12) ); } [Fact] public void FieldsSpan() { var text = @" using System; public class Program { static void Main() { } public static Span<byte> fs; public Span<int> fi; public ref struct S1 { public static Span<byte> fs1; public Span<int> fi1; } public struct S2 { public static Span<byte> fs2; public Span<int> fi2; } } "; CSharpCompilation comp = CreateCompilationWithMscorlibAndSpan(text); comp.VerifyDiagnostics( // (22,16): error CS8345: Field or auto-implemented property cannot be of type 'Span<int>' unless it is an instance member of a ref struct. // public Span<int> fi2; Diagnostic(ErrorCode.ERR_FieldAutoPropCantBeByRefLike, "Span<int>").WithArguments("System.Span<int>").WithLocation(22, 16), // (21,23): error CS8345: Field or auto-implemented property cannot be of type 'Span<byte>' unless it is an instance member of a ref struct. // public static Span<byte> fs2; Diagnostic(ErrorCode.ERR_FieldAutoPropCantBeByRefLike, "Span<byte>").WithArguments("System.Span<byte>").WithLocation(21, 23), // (10,19): error CS8345: Field or auto-implemented property cannot be of type 'Span<byte>' unless it is an instance member of a ref struct. // public static Span<byte> fs; Diagnostic(ErrorCode.ERR_FieldAutoPropCantBeByRefLike, "Span<byte>").WithArguments("System.Span<byte>").WithLocation(10, 19), // (11,12): error CS8345: Field or auto-implemented property cannot be of type 'Span<int>' unless it is an instance member of a ref struct. // public Span<int> fi; Diagnostic(ErrorCode.ERR_FieldAutoPropCantBeByRefLike, "Span<int>").WithArguments("System.Span<int>").WithLocation(11, 12), // (15,23): error CS8345: Field or auto-implemented property cannot be of type 'Span<byte>' unless it is an instance member of a ref struct. // public static Span<byte> fs1; Diagnostic(ErrorCode.ERR_FieldAutoPropCantBeByRefLike, "Span<byte>").WithArguments("System.Span<byte>").WithLocation(15, 23) ); comp = CreateCompilationWithMscorlibAndSpanSrc(text); comp.VerifyDiagnostics( // (22,16): error CS8345: Field or auto-implemented property cannot be of type 'Span<int>' unless it is an instance member of a ref struct. // public Span<int> fi2; Diagnostic(ErrorCode.ERR_FieldAutoPropCantBeByRefLike, "Span<int>").WithArguments("System.Span<int>").WithLocation(22, 16), // (21,23): error CS8345: Field or auto-implemented property cannot be of type 'Span<byte>' unless it is an instance member of a ref struct. // public static Span<byte> fs2; Diagnostic(ErrorCode.ERR_FieldAutoPropCantBeByRefLike, "Span<byte>").WithArguments("System.Span<byte>").WithLocation(21, 23), // (10,19): error CS8345: Field or auto-implemented property cannot be of type 'Span<byte>' unless it is an instance member of a ref struct. // public static Span<byte> fs; Diagnostic(ErrorCode.ERR_FieldAutoPropCantBeByRefLike, "Span<byte>").WithArguments("System.Span<byte>").WithLocation(10, 19), // (11,12): error CS8345: Field or auto-implemented property cannot be of type 'Span<int>' unless it is an instance member of a ref struct. // public Span<int> fi; Diagnostic(ErrorCode.ERR_FieldAutoPropCantBeByRefLike, "Span<int>").WithArguments("System.Span<int>").WithLocation(11, 12), // (15,23): error CS8345: Field or auto-implemented property cannot be of type 'Span<byte>' unless it is an instance member of a ref struct. // public static Span<byte> fs1; Diagnostic(ErrorCode.ERR_FieldAutoPropCantBeByRefLike, "Span<byte>").WithArguments("System.Span<byte>").WithLocation(15, 23) ); } [Fact] public void FieldsSpanLike() { var text = @" using System; public class Program { static void Main() { } public static SpanLike<byte> fs; public SpanLike<int> fi; public ref struct S1 { public static SpanLike<byte> fs1; public SpanLike<int> fi1; } public struct S2 { public static SpanLike<byte> fs2; public SpanLike<int> fi2; } } "; CSharpCompilation comp = CreateCompilationWithMscorlibAndSpan(text); comp.VerifyDiagnostics( // (22,16): error CS8345: Field or auto-implemented property cannot be of type 'SpanLike<int>' unless it is an instance member of a ref struct. // public SpanLike<int> fi2; Diagnostic(ErrorCode.ERR_FieldAutoPropCantBeByRefLike, "SpanLike<int>").WithArguments("System.SpanLike<int>").WithLocation(22, 16), // (21,23): error CS8345: Field or auto-implemented property cannot be of type 'SpanLike<byte>' unless it is an instance member of a ref struct. // public static SpanLike<byte> fs2; Diagnostic(ErrorCode.ERR_FieldAutoPropCantBeByRefLike, "SpanLike<byte>").WithArguments("System.SpanLike<byte>").WithLocation(21, 23), // (10,19): error CS8345: Field or auto-implemented property cannot be of type 'SpanLike<byte>' unless it is an instance member of a ref struct. // public static SpanLike<byte> fs; Diagnostic(ErrorCode.ERR_FieldAutoPropCantBeByRefLike, "SpanLike<byte>").WithArguments("System.SpanLike<byte>").WithLocation(10, 19), // (11,12): error CS8345: Field or auto-implemented property cannot be of type 'SpanLike<int>' unless it is an instance member of a ref struct. // public SpanLike<int> fi; Diagnostic(ErrorCode.ERR_FieldAutoPropCantBeByRefLike, "SpanLike<int>").WithArguments("System.SpanLike<int>").WithLocation(11, 12), // (15,23): error CS8345: Field or auto-implemented property cannot be of type 'SpanLike<byte>' unless it is an instance member of a ref struct. // public static SpanLike<byte> fs1; Diagnostic(ErrorCode.ERR_FieldAutoPropCantBeByRefLike, "SpanLike<byte>").WithArguments("System.SpanLike<byte>").WithLocation(15, 23) ); comp = CreateCompilationWithMscorlibAndSpanSrc(text); comp.VerifyDiagnostics( // (22,16): error CS8345: Field or auto-implemented property cannot be of type 'SpanLike<int>' unless it is an instance member of a ref struct. // public SpanLike<int> fi2; Diagnostic(ErrorCode.ERR_FieldAutoPropCantBeByRefLike, "SpanLike<int>").WithArguments("System.SpanLike<int>").WithLocation(22, 16), // (21,23): error CS8345: Field or auto-implemented property cannot be of type 'SpanLike<byte>' unless it is an instance member of a ref struct. // public static SpanLike<byte> fs2; Diagnostic(ErrorCode.ERR_FieldAutoPropCantBeByRefLike, "SpanLike<byte>").WithArguments("System.SpanLike<byte>").WithLocation(21, 23), // (10,19): error CS8345: Field or auto-implemented property cannot be of type 'SpanLike<byte>' unless it is an instance member of a ref struct. // public static SpanLike<byte> fs; Diagnostic(ErrorCode.ERR_FieldAutoPropCantBeByRefLike, "SpanLike<byte>").WithArguments("System.SpanLike<byte>").WithLocation(10, 19), // (11,12): error CS8345: Field or auto-implemented property cannot be of type 'SpanLike<int>' unless it is an instance member of a ref struct. // public SpanLike<int> fi; Diagnostic(ErrorCode.ERR_FieldAutoPropCantBeByRefLike, "SpanLike<int>").WithArguments("System.SpanLike<int>").WithLocation(11, 12), // (15,23): error CS8345: Field or auto-implemented property cannot be of type 'SpanLike<byte>' unless it is an instance member of a ref struct. // public static SpanLike<byte> fs1; Diagnostic(ErrorCode.ERR_FieldAutoPropCantBeByRefLike, "SpanLike<byte>").WithArguments("System.SpanLike<byte>").WithLocation(15, 23) ); } [Fact] public void SpanToImplicitHeapMemory() { var source = @" class Test { static void Method1(int[] array) { var a = new { P = stackalloc int[3] { 1, 2, 3 } }; var b = (dynamic)stackalloc int[3] { 1, 2, 3 }; } }"; CreateCompilationWithMscorlibAndSpan(source, TestOptions.ReleaseDll) .VerifyDiagnostics( // (6,23): error CS0828: Cannot assign 'Span<int>' to anonymous type property // var a = new { P = stackalloc int[3] { 1, 2, 3 } }; Diagnostic(ErrorCode.ERR_AnonymousTypePropertyAssignedBadValue, "P = stackalloc int[3] { 1, 2, 3 }").WithArguments("System.Span<int>").WithLocation(6, 23), // (7,17): error CS8346: Conversion of a stackalloc expression of type 'int' to type 'dynamic' is not possible. // var b = (dynamic)stackalloc int[3] { 1, 2, 3 }; Diagnostic(ErrorCode.ERR_StackAllocConversionNotPossible, "(dynamic)stackalloc int[3] { 1, 2, 3 }").WithArguments("int", "dynamic").WithLocation(7, 17) ); } [Fact] public void SpanToImplicitHeapMemoryInLinq() { var source = @" using System; using System.Linq; using System.Collections.Generic; class Test { static void Method1(int[] array) { var array2 = new int[] { 1, 2, 3 }; unsafe { var strs = from x in _M<int>() #line 100 from y in _M<string>() #line 200 let l = x #line 300 let m = _GetPointer() #line 400 let n = _GetDelegatePointer() select x.ToString() + y.ToString(); } var q = from c in array #line 500 from x in _M<int>() join p in array2 on c equals p into g select g; var q2 = from x in _M<int>() #line 600 from y in _M<string>() group x by y into g select g; #line 700 var q3 = from x in _M<int>() let y = 2 select x[0] + y; static IEnumerable<Span<T>> _M<T>() { throw new Exception(); } static void* _GetPointer() { throw new Exception(); } static delegate*<int> _GetDelegatePointer() { throw new Exception(); } } } public static class MyExtensions { public static IEnumerable<MyGrouping<TKey, TElement>> GroupBy<TSource, TKey, TElement>(this IEnumerable<TSource> sources, Func<TSource, TKey> keyFactory, Func<TSource, TElement> elementFactory) where TSource : allows ref struct where TKey : allows ref struct where TElement : allows ref struct { throw new Exception(); } public class MyGrouping<TKey, TElement> where TKey : allows ref struct where TElement : allows ref struct { } public static IEnumerable<TResult> SelectMany<TSource, TCollection, TResult>(this IEnumerable<TSource> sources, Func<TSource, IEnumerable<TCollection>> collectionsFactory, Func<TSource, TCollection, TResult> selector) where TSource : allows ref struct where TCollection : allows ref struct where TResult : allows ref struct { throw new Exception(); } } "; var comp = CreateCompilation(source, options: TestOptions.ReleaseDll.WithAllowUnsafe(true), targetFramework: TargetFramework.Net90); comp.VerifyDiagnostics( // (100,24): error CS0828: Cannot assign 'Span<string>' to anonymous type property // from y in _M<string>() Diagnostic(ErrorCode.ERR_AnonymousTypePropertyAssignedBadValue, "from y in _M<string>()").WithArguments("System.Span<string>").WithLocation(100, 24), // (200,24): error CS0828: Cannot assign 'Span<int>' to anonymous type property // let l = x Diagnostic(ErrorCode.ERR_AnonymousTypePropertyAssignedBadValue, "let l = x").WithArguments("System.Span<int>").WithLocation(200, 24), // (300,24): error CS0828: Cannot assign 'void*' to anonymous type property // let m = _GetPointer() Diagnostic(ErrorCode.ERR_AnonymousTypePropertyAssignedBadValue, "let m = _GetPointer()").WithArguments("void*").WithLocation(300, 24), // (400,24): error CS0828: Cannot assign 'delegate*<int>' to anonymous type property // let n = _GetDelegatePointer() Diagnostic(ErrorCode.ERR_AnonymousTypePropertyAssignedBadValue, "let n = _GetDelegatePointer()").WithArguments("delegate*<int>").WithLocation(400, 24), // (500,17): error CS0828: Cannot assign 'Span<int>' to anonymous type property // from x in _M<int>() Diagnostic(ErrorCode.ERR_AnonymousTypePropertyAssignedBadValue, "from x in _M<int>()").WithArguments("System.Span<int>").WithLocation(500, 17), // (600,18): error CS0828: Cannot assign 'Span<string>' to anonymous type property // from y in _M<string>() Diagnostic(ErrorCode.ERR_AnonymousTypePropertyAssignedBadValue, "from y in _M<string>()").WithArguments("System.Span<string>").WithLocation(600, 18), // (701,18): error CS0828: Cannot assign 'Span<int>' to anonymous type property // let y = 2 Diagnostic(ErrorCode.ERR_AnonymousTypePropertyAssignedBadValue, "let y = 2").WithArguments("System.Span<int>").WithLocation(701, 18) ); } [WorkItem(20226, "https://github.com/dotnet/roslyn/issues/20226")] [Fact] public void InterfaceImpl_01() { var text = @" using System; public class Program { static void Main(string[] args) { using (new S1()) { System.Console.Write(1); } System.Console.Write(3); } public ref struct S1 : IDisposable { public void Dispose() { System.Console.Write(2); } } } "; CSharpCompilation comp = CreateCompilationWithMscorlibAndSpan(text, options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: @"123").VerifyDiagnostics(); verifier.VerifyIL("Program.Main", @" { // Code size 31 (0x1f) .maxstack 1 .locals init (Program.S1 V_0) IL_0000: ldloca.s V_0 IL_0002: initobj ""Program.S1"" .try { IL_0008: ldc.i4.1 IL_0009: call ""void System.Console.Write(int)"" IL_000e: leave.s IL_0018 } finally { IL_0010: ldloca.s V_0 IL_0012: call ""void Program.S1.Dispose()"" IL_0017: endfinally } IL_0018: ldc.i4.3 IL_0019: call ""void System.Console.Write(int)"" IL_001e: ret } "); } [Fact] public void InterfaceImpl_02() { var text = @" using System; public class Program { static void Main(string[] args) { using (new S1()) { System.Console.Write(1); } System.Console.Write(3); } public ref struct S1 : IDisposable { public void Dispose() { System.Console.Write(22); } void IDisposable.Dispose() { System.Console.Write(2); } } } "; CSharpCompilation comp = CreateCompilationWithMscorlibAndSpan(text, options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: @"1223").VerifyDiagnostics(); // We prioritize pattern over an interface according to https://github.com/dotnet/csharplang/blob/main/proposals/ref-struct-interfaces.md#using-statement verifier.VerifyIL("Program.Main", @" { // Code size 31 (0x1f) .maxstack 1 .locals init (Program.S1 V_0) IL_0000: ldloca.s V_0 IL_0002: initobj ""Program.S1"" .try { IL_0008: ldc.i4.1 IL_0009: call ""void System.Console.Write(int)"" IL_000e: leave.s IL_0018 } finally { IL_0010: ldloca.s V_0 IL_0012: call ""void Program.S1.Dispose()"" IL_0017: endfinally } IL_0018: ldc.i4.3 IL_0019: call ""void System.Console.Write(int)"" IL_001e: ret } "); } [Fact] public void InterfaceImpl_03() { var text = @" using System; public class Program { static void Main(string[] args) { using (new S1()) { System.Console.Write(1); } System.Console.Write(3); } public ref struct S1 : IDisposable { void IDisposable.Dispose() { System.Console.Write(2); } } } "; CSharpCompilation comp = CreateCompilationWithMscorlibAndSpan(text, options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: @"123").VerifyDiagnostics(); verifier.VerifyIL("Program.Main", @" { // Code size 37 (0x25) .maxstack 1 .locals init (Program.S1 V_0) IL_0000: ldloca.s V_0 IL_0002: initobj ""Program.S1"" .try { IL_0008: ldc.i4.1 IL_0009: call ""void System.Console.Write(int)"" IL_000e: leave.s IL_001e } finally { IL_0010: ldloca.s V_0 IL_0012: constrained. ""Program.S1"" IL_0018: callvirt ""void System.IDisposable.Dispose()"" IL_001d: endfinally } IL_001e: ldc.i4.3 IL_001f: call ""void System.Console.Write(int)"" IL_0024: ret } "); } [Fact] public void NoInterfaceImp() { var text = @" public class Program { static void Main(string[] args) { using (new S1()) { System.Console.Write(1); } System.Console.Write(3); } public ref struct S1 { public void Dispose() { System.Console.Write(2); } } } "; CSharpCompilation comp = CreateCompilationWithMscorlibAndSpan(text, options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: @"123").VerifyDiagnostics(); verifier.VerifyIL("Program.Main", @" { // Code size 31 (0x1f) .maxstack 1 .locals init (Program.S1 V_0) IL_0000: ldloca.s V_0 IL_0002: initobj ""Program.S1"" .try { IL_0008: ldc.i4.1 IL_0009: call ""void System.Console.Write(int)"" IL_000e: leave.s IL_0018 } finally { IL_0010: ldloca.s V_0 IL_0012: call ""void Program.S1.Dispose()"" IL_0017: endfinally } IL_0018: ldc.i4.3 IL_0019: call ""void System.Console.Write(int)"" IL_001e: ret } "); } [WorkItem(20226, "https://github.com/dotnet/roslyn/issues/20226")] [Fact] public void RefIteratorInAsync_01() { var text = @" using System; using System.Threading.Tasks; class Program { static void Main(string[] args) { } static async Task<int> Test() { var obj = new C1(); foreach (var i in obj) { await Task.Yield(); System.Console.WriteLine(i); } return 123; } } class C1 { public S1 GetEnumerator() { return new S1(); } public ref struct S1 { public int Current => throw new NotImplementedException(); public bool MoveNext() { throw new NotImplementedException(); } } } "; CreateCompilationWithMscorlibAndSpan(text, parseOptions: TestOptions.Regular12).VerifyDiagnostics( // (15,9): error CS9202: Feature 'ref and unsafe in async and iterator methods' is not available in C# 12.0. Please use language version 13.0 or greater. // foreach (var i in obj) Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion12, "foreach").WithArguments("ref and unsafe in async and iterator methods", "13.0").WithLocation(15, 9)); var expectedDiagnostics = new[] { // (15,9): error CS4007: Instance of type 'C1.S1' cannot be preserved across 'await' or 'yield' boundary. // foreach (var i in obj) Diagnostic(ErrorCode.ERR_ByRefTypeAndAwait, @"foreach (var i in obj) { await Task.Yield(); System.Console.WriteLine(i); }").WithArguments("C1.S1").WithLocation(15, 9) }; CreateCompilationWithMscorlibAndSpan(text, parseOptions: TestOptions.Regular13).VerifyEmitDiagnostics(expectedDiagnostics); CreateCompilationWithMscorlibAndSpan(text).VerifyEmitDiagnostics(expectedDiagnostics); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/74793")] public void RefIteratorInAsync_02() { var text = @" using System.Threading.Tasks; class Program { static async Task Main() { var obj = new C1(); foreach (var i in obj) { System.Console.Write(i); } await Task.Yield(); System.Console.Write(-1); } } class C1 { public S1 GetEnumerator() { return new S1(); } public ref struct S1 { public int Current { get; private set; } public bool MoveNext() { Current++; return Current < 3; } } } "; CreateCompilationWithMscorlibAndSpan(text, parseOptions: TestOptions.Regular12).VerifyDiagnostics( // (10,9): error CS9202: Feature 'ref and unsafe in async and iterator methods' is not available in C# 12.0. Please use language version 13.0 or greater. // foreach (var i in obj) Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion12, "foreach").WithArguments("ref and unsafe in async and iterator methods", "13.0").WithLocation(10, 9)); var expectedOutput = "12-1"; var comp = CreateCompilationWithMscorlibAndSpan(text, TestOptions.ReleaseExe, TestOptions.Regular13); CompileAndVerify(comp, expectedOutput: expectedOutput, verify: Verification.FailsILVerify).VerifyDiagnostics(); comp = CreateCompilationWithMscorlibAndSpan(text, TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: expectedOutput, verify: Verification.FailsILVerify).VerifyDiagnostics(); } [WorkItem(20226, "https://github.com/dotnet/roslyn/issues/20226")] [Fact] public void RefIteratorInIterator_01() { var text = @" using System; using System.Collections.Generic; class Program { static void Main(string[] args) { // this is valid Action a = () => { foreach (var i in new C1()) { } }; a(); } static IEnumerable<int> Test() { // this is valid Action a = () => { foreach (var i in new C1()) { } }; a(); // this is an error foreach (var i in new C1()) { yield return 0; } yield return 1; } } class C1 { public S1 GetEnumerator() { return new S1(); } public ref struct S1 { public int Current => throw new NotImplementedException(); public bool MoveNext() { throw new NotImplementedException(); } } } "; CreateCompilationWithMscorlibAndSpan(text, parseOptions: TestOptions.Regular12).VerifyDiagnostics( // (33,9): error CS9202: Feature 'ref and unsafe in async and iterator methods' is not available in C# 12.0. Please use language version 13.0 or greater. // foreach (var i in new C1()) Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion12, "foreach").WithArguments("ref and unsafe in async and iterator methods", "13.0").WithLocation(33, 9)); var expectedDiagnostics = new[] { // (33,9): error CS4007: Instance of type 'C1.S1' cannot be preserved across 'await' or 'yield' boundary. // foreach (var i in new C1()) Diagnostic(ErrorCode.ERR_ByRefTypeAndAwait, @"foreach (var i in new C1()) { yield return 0; }").WithArguments("C1.S1").WithLocation(33, 9) }; CreateCompilationWithMscorlibAndSpan(text, parseOptions: TestOptions.Regular13).VerifyEmitDiagnostics(expectedDiagnostics); CreateCompilationWithMscorlibAndSpan(text).VerifyEmitDiagnostics(expectedDiagnostics); } [Fact] public void RefIteratorInIterator_02() { var text = @" using System; using System.Collections.Generic; class Program { static void Main(string[] args) { foreach (var i in Test()) { Console.Write(i); } } static IEnumerable<int> Test() { foreach (var i in new C1()) { Console.Write(i); } yield return -1; Console.Write(-2); } } class C1 { public S1 GetEnumerator() { return new S1(); } public ref struct S1 { public int Current { get; private set; } public bool MoveNext() { Current++; return Current < 3; } } } "; CreateCompilationWithMscorlibAndSpan(text, TestOptions.ReleaseExe, TestOptions.Regular12).VerifyDiagnostics( // (17,9): error CS9202: Feature 'ref and unsafe in async and iterator methods' is not available in C# 12.0. Please use language version 13.0 or greater. // foreach (var i in new C1()) Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion12, "foreach").WithArguments("ref and unsafe in async and iterator methods", "13.0").WithLocation(17, 9)); var expectedOutput = "12-1-2"; var comp = CreateCompilationWithMscorlibAndSpan(text, TestOptions.ReleaseExe, TestOptions.Regular13); CompileAndVerify(comp, expectedOutput: expectedOutput, verify: Verification.FailsILVerify).VerifyDiagnostics(); comp = CreateCompilationWithMscorlibAndSpan(text, TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: expectedOutput, verify: Verification.FailsILVerify).VerifyDiagnostics(); } [Fact] public void Properties() { var text = @" using System; public class Program { static void Main() { } // valid public static Span<byte> ps => default(Span<byte>); public Span<int> pi => default(Span<int>); public Span<int> this[int i] => default(Span<int>); // not valid public static Span<byte> aps {get;} public Span<int> api {get; set;} } "; CSharpCompilation comp = CreateCompilationWithMscorlibAndSpan(text); comp.VerifyDiagnostics( // (17,19): error CS8345: Field or auto-implemented property cannot be of type 'Span<byte>' unless it is an instance member of a ref struct. // public static Span<byte> aps {get;} Diagnostic(ErrorCode.ERR_FieldAutoPropCantBeByRefLike, "Span<byte>").WithArguments("System.Span<byte>").WithLocation(17, 19), // (18,12): error CS8345: Field or auto-implemented property cannot be of type 'Span<int>' unless it is an instance member of a ref struct. // public Span<int> api {get; set;} Diagnostic(ErrorCode.ERR_FieldAutoPropCantBeByRefLike, "Span<int>").WithArguments("System.Span<int>").WithLocation(18, 12) ); } [Fact] public void Operators() { var text = @" using System; public class Program { static void Main() { } // valid public static Span<byte> operator +(Span<byte> x, Program y) => default(Span<byte>); // invalid (baseline w/ TypedReference) public static TypedReference operator +(Span<int> x, Program y) => default(TypedReference); } "; CSharpCompilation comp = CreateCompilationWithMscorlibAndSpan(text); comp.VerifyDiagnostics( // (14,19): error CS1599: The return type of a method, delegate, or function pointer cannot be 'TypedReference' // public static TypedReference operator +(Span<int> x, Program y) => default(TypedReference); Diagnostic(ErrorCode.ERR_MethodReturnCantBeRefAny, "TypedReference").WithArguments("System.TypedReference").WithLocation(14, 19) ); } [Fact] public void AsyncParams() { var text = @" using System; using System.Threading.Tasks; public class Program { static void Main() { } public static async Task<int> M1(Span<int> arg) { await Task.Yield(); return 42; } } "; CSharpCompilation comp = CreateCompilationWithMscorlibAndSpan(text); comp.VerifyDiagnostics( // (11,48): error CS4012: Parameters of type 'Span<int>' cannot be declared in async methods or async lambda expressions. // public static async Task<int> M1(Span<int> arg) Diagnostic(ErrorCode.ERR_BadSpecialByRefParameter, "arg").WithArguments("System.Span<int>").WithLocation(11, 48) ); } [Fact] public void AsyncLocals() { var text = @" using System; using System.Threading.Tasks; public class Program { static void Main() { } public static async Task<int> M1() { Span<int> local1 = default(Span<int>); var local2 = default(Span<int>); await Task.Yield(); return 42; } public static async Task<int> M2() { Span<int> local1 = default(Span<int>); var local2 = default(Span<int>); await Task.Yield(); return local1.Length; // 1 } public static async Task<int> M3() { Span<int> local1 = default(Span<int>); var local2 = default(Span<int>); await Task.Yield(); return local2.Length; // 2 } public static async Task<int> M4() { Span<int> local1 = default(Span<int>); var local2 = default(Span<int>); await Task.Yield(); return local1.Length + local2.Length; // 3, 4 } } "; var expectedDiagnostics = new[] { // (13,19): warning CS0219: The variable 'local1' is assigned but its value is never used // Span<int> local1 = default(Span<int>); Diagnostic(ErrorCode.WRN_UnreferencedVarAssg, "local1").WithArguments("local1").WithLocation(13, 19), // (14,13): warning CS0219: The variable 'local2' is assigned but its value is never used // var local2 = default(Span<int>); Diagnostic(ErrorCode.WRN_UnreferencedVarAssg, "local2").WithArguments("local2").WithLocation(14, 13), // (23,13): warning CS0219: The variable 'local2' is assigned but its value is never used // var local2 = default(Span<int>); Diagnostic(ErrorCode.WRN_UnreferencedVarAssg, "local2").WithArguments("local2").WithLocation(23, 13), // (26,16): error CS4007: Instance of type 'System.Span<int>' cannot be preserved across 'await' or 'yield' boundary. // return local1.Length; // 1 Diagnostic(ErrorCode.ERR_ByRefTypeAndAwait, "local1").WithArguments("System.Span<int>").WithLocation(26, 16), // (31,19): warning CS0219: The variable 'local1' is assigned but its value is never used // Span<int> local1 = default(Span<int>); Diagnostic(ErrorCode.WRN_UnreferencedVarAssg, "local1").WithArguments("local1").WithLocation(31, 19), // (35,16): error CS4007: Instance of type 'System.Span<int>' cannot be preserved across 'await' or 'yield' boundary. // return local2.Length; // 2 Diagnostic(ErrorCode.ERR_ByRefTypeAndAwait, "local2").WithArguments("System.Span<int>").WithLocation(35, 16), // (44,16): error CS4007: Instance of type 'System.Span<int>' cannot be preserved across 'await' or 'yield' boundary. // return local1.Length + local2.Length; // 3, 4 Diagnostic(ErrorCode.ERR_ByRefTypeAndAwait, "local1").WithArguments("System.Span<int>").WithLocation(44, 16), // (44,32): error CS4007: Instance of type 'System.Span<int>' cannot be preserved across 'await' or 'yield' boundary. // return local1.Length + local2.Length; // 3, 4 Diagnostic(ErrorCode.ERR_ByRefTypeAndAwait, "local2").WithArguments("System.Span<int>").WithLocation(44, 32) }; CSharpCompilation comp = CreateCompilationWithMscorlibAndSpan(text); comp.VerifyEmitDiagnostics(expectedDiagnostics); comp = CreateCompilationWithMscorlibAndSpan(text, TestOptions.DebugExe); comp.VerifyEmitDiagnostics(expectedDiagnostics); } [Fact] public void AsyncLocals_OutVar() { var text = @" using System; using System.Threading.Tasks; public class Program { public static async Task<int> M1() { M2(out var local1); M2(out Span<int> local2); await Task.Yield(); return 42; } public static async Task<int> M3() { M2(out var local1); M2(out Span<int> local2); await Task.Yield(); return local1.Length; // 1 } public static async Task<int> M4() { M2(out var local1); M2(out Span<int> local2); await Task.Yield(); return local2.Length; // 2 } static void M2(out Span<int> s) => throw null; } "; CSharpCompilation comp = CreateCompilationWithMscorlibAndSpan(text); comp.VerifyEmitDiagnostics( // (22,16): error CS4007: Instance of type 'System.Span<int>' cannot be preserved across 'await' or 'yield' boundary. // return local1.Length; // 1 Diagnostic(ErrorCode.ERR_ByRefTypeAndAwait, "local1").WithArguments("System.Span<int>").WithLocation(22, 16), // (31,16): error CS4007: Instance of type 'System.Span<int>' cannot be preserved across 'await' or 'yield' boundary. // return local2.Length; // 2 Diagnostic(ErrorCode.ERR_ByRefTypeAndAwait, "local2").WithArguments("System.Span<int>").WithLocation(31, 16)); } [Fact, WorkItem(62747, "https://github.com/dotnet/roslyn/issues/62747")] public void AsyncLocals_Foreach() { var src = @" using System; using System.Collections.Generic; using System.Threading.Tasks; public class Program { public async Task M(IReadOnlyList<string> o) { foreach (ReadOnlySpan<char> c1 in o) { } var enumerator = ((IEnumerable<string>)o).GetEnumerator(); while (enumerator.MoveNext()) { ReadOnlySpan<char> c2 = (ReadOnlySpan<char>)(string)enumerator.Current; _ = c2.Length; } await Task.Yield(); return; } public async Task M2(IReadOnlyList<string> o) { foreach (ReadOnlySpan<char> c1 in o) { await Task.Yield(); _ = c1.Length; // 1 } var enumerator = ((IEnumerable<string>)o).GetEnumerator(); while (enumerator.MoveNext()) { ReadOnlySpan<char> c2 = (ReadOnlySpan<char>)(string)enumerator.Current; await Task.Yield(); _ = c2.Length; // 2 } await Task.Yield(); return; } } "; var comp = CreateCompilation(src, targetFramework: TargetFramework.Net70); comp.VerifyEmitDiagnostics( // (28,17): error CS4007: Instance of type 'System.ReadOnlySpan<char>' cannot be preserved across 'await' or 'yield' boundary. // _ = c1.Length; // 1 Diagnostic(ErrorCode.ERR_ByRefTypeAndAwait, "c1").WithArguments("System.ReadOnlySpan<char>").WithLocation(28, 17), // (36,17): error CS4007: Instance of type 'System.ReadOnlySpan<char>' cannot be preserved across 'await' or 'yield' boundary. // _ = c2.Length; // 2 Diagnostic(ErrorCode.ERR_ByRefTypeAndAwait, "c2").WithArguments("System.ReadOnlySpan<char>").WithLocation(36, 17)); } [Fact, WorkItem(62747, "https://github.com/dotnet/roslyn/issues/62747")] public void AsyncLocals_Deconstruction() { var src = @" using System; using System.Threading.Tasks; public class Program { public async Task M() { (Span<int> s1, Span<int> s2) = new Program(); var (s3, s4) = new Program(); (var s5, var s6) = new Program(); await Task.Yield(); return; } public async Task M2() { (Span<int> s1, Span<int> s2) = new Program(); var (s3, s4) = new Program(); (var s5, var s6) = new Program(); await Task.Yield(); _ = s1.Length + s4.Length + s5.Length; // 1, 2, 3 return; } void Deconstruct(out Span<int> s1, out Span<int> s2) => throw null; } "; var comp = CreateCompilation(src, targetFramework: TargetFramework.Net70); comp.VerifyEmitDiagnostics( // (25,13): error CS4007: Instance of type 'System.Span<int>' cannot be preserved across 'await' or 'yield' boundary. // _ = s1.Length + s4.Length + s5.Length; // 1, 2, 3 Diagnostic(ErrorCode.ERR_ByRefTypeAndAwait, "s1").WithArguments("System.Span<int>").WithLocation(25, 13), // (25,25): error CS4007: Instance of type 'System.Span<int>' cannot be preserved across 'await' or 'yield' boundary. // _ = s1.Length + s4.Length + s5.Length; // 1, 2, 3 Diagnostic(ErrorCode.ERR_ByRefTypeAndAwait, "s4").WithArguments("System.Span<int>").WithLocation(25, 25), // (25,37): error CS4007: Instance of type 'System.Span<int>' cannot be preserved across 'await' or 'yield' boundary. // _ = s1.Length + s4.Length + s5.Length; // 1, 2, 3 Diagnostic(ErrorCode.ERR_ByRefTypeAndAwait, "s5").WithArguments("System.Span<int>").WithLocation(25, 37)); } [Fact, WorkItem(62747, "https://github.com/dotnet/roslyn/issues/62747")] public void AsyncLocals_Using() { var src = @" using System.Threading.Tasks; public class Program { public async Task M() { using (default(RS)) { } using (var s1 = default(RS)) { } using (RS s2 = default(RS)) { } using RS s3 = default(RS); // 1 using var s4 = default(RS); // 2 await Task.Yield(); return; } public async Task M2() { using (default(RS)) { await Task.Yield(); } // 3 using (var s1 = default(RS)) { await Task.Yield(); } // 4 using (RS s2 = default(RS)) { await Task.Yield(); } // 5 { using RS s3 = default(RS); // 6 await Task.Yield(); using var s4 = default(RS); } await Task.Yield(); return; } } public ref struct RS { public void Dispose() { } } "; var comp = CreateCompilation(src, targetFramework: TargetFramework.Net70); comp.VerifyEmitDiagnostics( // (11,18): error CS4007: Instance of type 'RS' cannot be preserved across 'await' or 'yield' boundary. // using RS s3 = default(RS); // 1 Diagnostic(ErrorCode.ERR_ByRefTypeAndAwait, "s3 = default(RS)").WithArguments("RS").WithLocation(11, 18), // (12,19): error CS4007: Instance of type 'RS' cannot be preserved across 'await' or 'yield' boundary. // using var s4 = default(RS); // 2 Diagnostic(ErrorCode.ERR_ByRefTypeAndAwait, "s4 = default(RS)").WithArguments("RS").WithLocation(12, 19), // (20,16): error CS4007: Instance of type 'RS' cannot be preserved across 'await' or 'yield' boundary. // using (default(RS)) { await Task.Yield(); } // 3 Diagnostic(ErrorCode.ERR_ByRefTypeAndAwait, "default(RS)").WithArguments("RS").WithLocation(20, 16), // (21,20): error CS4007: Instance of type 'RS' cannot be preserved across 'await' or 'yield' boundary. // using (var s1 = default(RS)) { await Task.Yield(); } // 4 Diagnostic(ErrorCode.ERR_ByRefTypeAndAwait, "s1 = default(RS)").WithArguments("RS").WithLocation(21, 20), // (22,19): error CS4007: Instance of type 'RS' cannot be preserved across 'await' or 'yield' boundary. // using (RS s2 = default(RS)) { await Task.Yield(); } // 5 Diagnostic(ErrorCode.ERR_ByRefTypeAndAwait, "s2 = default(RS)").WithArguments("RS").WithLocation(22, 19), // (24,22): error CS4007: Instance of type 'RS' cannot be preserved across 'await' or 'yield' boundary. // using RS s3 = default(RS); // 6 Diagnostic(ErrorCode.ERR_ByRefTypeAndAwait, "s3 = default(RS)").WithArguments("RS").WithLocation(24, 22)); } [Fact] public void AsyncLocals_PatternDeclaration() { var src = @" using System; using System.Threading.Tasks; public class Program { public async Task M() { if (M2() is var s1) { } if (M2() is Span<int> s2) { } if (M2() is var s3) { await Task.Yield(); } if (M2() is Span<int> s4) { await Task.Yield(); } await Task.Yield(); return; } public async Task M3() { if (M2() is var s1) { await Task.Yield(); _ = s1.Length; // 1 } if (M2() is Span<int> s2) { await Task.Yield(); _ = s2.Length; // 2 } await Task.Yield(); return; } static Span<int> M2() => throw null; } "; var comp = CreateCompilation(src, targetFramework: TargetFramework.Net70); comp.VerifyEmitDiagnostics( // (23,17): error CS4007: Instance of type 'System.Span<int>' cannot be preserved across 'await' or 'yield' boundary. // _ = s1.Length; Diagnostic(ErrorCode.ERR_ByRefTypeAndAwait, "s1").WithArguments("System.Span<int>").WithLocation(23, 17), // (28,17): error CS4007: Instance of type 'System.Span<int>' cannot be preserved across 'await' or 'yield' boundary. // _ = s2.Length; Diagnostic(ErrorCode.ERR_ByRefTypeAndAwait, "s2").WithArguments("System.Span<int>").WithLocation(28, 17)); } [Fact] public void AsyncLocals_Reassignment() { var code = """ using System; using System.Threading.Tasks; class C { async Task M1() { int x = 42; Span<int> y = new(ref x); y.ToString(); await Task.Yield(); y.ToString(); // 1 } async Task M2() { int x = 42; Span<int> y = new(ref x); y.ToString(); await Task.Yield(); y = new(ref x); y.ToString(); } } """; CreateCompilation(code, targetFramework: TargetFramework.Net70).VerifyEmitDiagnostics( // (11,9): error CS4007: Instance of type 'System.Span<int>' cannot be preserved across 'await' or 'yield' boundary. // y.ToString(); // 1 Diagnostic(ErrorCode.ERR_ByRefTypeAndAwait, "y").WithArguments("System.Span<int>").WithLocation(11, 9)); } [Fact] public void AsyncSpilling() { var text = @" using System; using System.Threading.Tasks; public class Program { static void Main() { } public static async Task<int> M1() { // this is ok TakesSpan(default(Span<int>), 123); // this is not ok TakesSpan(default(Span<int>), await I1()); // this is ok TakesSpan(await I1(), default(Span<int>)); return 42; } public static void TakesSpan(Span<int> s, int i) { } public static void TakesSpan(int i, Span<int> s) { } public static async Task<int> I1() { await Task.Yield(); return 42; } } "; CSharpCompilation comp = CreateCompilationWithMscorlibAndSpan(text); var expectedDiagnostics = new[] { // (17,19): error CS4007: Instance of type 'System.Span<int>' cannot be preserved across 'await' or 'yield' boundary. // TakesSpan(default(Span<int>), await I1()); Diagnostic(ErrorCode.ERR_ByRefTypeAndAwait, "default(Span<int>)").WithArguments("System.Span<int>").WithLocation(17, 19) }; comp.VerifyEmitDiagnostics(expectedDiagnostics); comp = CreateCompilationWithMscorlibAndSpan(text, TestOptions.DebugExe); comp.VerifyEmitDiagnostics(expectedDiagnostics); } [Fact] public void AsyncSpillTemp() { var text = @" using System; using System.Threading.Tasks; public class Program { static void Main() { } public static async Task<int> M1() { // this is not ok TakesSpan(s: default(Span<int>), i: await I1()); return 42; } public static void TakesSpan(int i, Span<int> s) { } public static async Task<int> I1() { await Task.Yield(); return 42; } } "; CSharpCompilation comp = CreateCompilationWithMscorlibAndSpan(text); var expectedDiagnostics = new[] { // (14,22): error CS4007: Instance of type 'System.Span<int>' cannot be preserved across 'await' or 'yield' boundary. // TakesSpan(s: default(Span<int>), i: await I1()); Diagnostic(ErrorCode.ERR_ByRefTypeAndAwait, "default(Span<int>)").WithArguments("System.Span<int>").WithLocation(14, 22) }; comp.VerifyEmitDiagnostics(expectedDiagnostics); comp = CreateCompilationWithMscorlibAndSpan(text, TestOptions.DebugExe); comp.VerifyEmitDiagnostics(expectedDiagnostics); } [Fact] public void AwaitAssignSpan() { var source = """ using System; using System.Threading.Tasks; ReadOnlySpan<int> r = await M(); Console.Write(r[1]); async Task<int[]> M() { await Task.Yield(); return new[] { 4, 5, 6 }; } """; CreateCompilationWithSpan(source, parseOptions: TestOptions.Regular12).VerifyDiagnostics( // (4,1): error CS9202: Feature 'ref and unsafe in async and iterator methods' is not available in C# 12.0. Please use language version 13.0 or greater. // ReadOnlySpan<int> r = await M(); Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion12, "ReadOnlySpan<int>").WithArguments("ref and unsafe in async and iterator methods", "13.0").WithLocation(4, 1)); var expectedOutput = "5"; var comp = CreateCompilationWithSpan(source, parseOptions: TestOptions.Regular13); CompileAndVerify(comp, expectedOutput: expectedOutput).VerifyDiagnostics(); comp = CreateCompilationWithSpan(source); CompileAndVerify(comp, expectedOutput: expectedOutput).VerifyDiagnostics(); } [Fact] public void BaseMethods() { var text = @" using System; public class Program { static void Main() { // this is ok (overridden) default(Span<int>).GetHashCode(); // this is ok (implicit boxing) default(Span<int>).GetType(); // this is not ok (implicit boxing) default(Span<int>).ToString(); } } "; CSharpCompilation comp = CreateCompilationWithMscorlibAndSpan(text); comp.VerifyDiagnostics( // (12,9): error CS0029: Cannot implicitly convert type 'System.Span<int>' to 'object' // default(Span<int>).GetType(); Diagnostic(ErrorCode.ERR_NoImplicitConv, "default(Span<int>)").WithArguments("System.Span<int>", "object").WithLocation(12, 9), // (15,9): error CS0029: Cannot implicitly convert type 'System.Span<int>' to 'System.ValueType' // default(Span<int>).ToString(); Diagnostic(ErrorCode.ERR_NoImplicitConv, "default(Span<int>)").WithArguments("System.Span<int>", "System.ValueType").WithLocation(15, 9) ); } [WorkItem(21979, "https://github.com/dotnet/roslyn/issues/21979")] [Fact] public void MethodConversion() { var text = @" using System; public class Program { static void Main() { // we no longer allow this. // see https://github.com/dotnet/roslyn/issues/21979 Func<int> d0 = default(TypedReference).GetHashCode; // none of the following is ok, since we would need to capture the receiver. Func<int> d1 = default(Span<int>).GetHashCode; Func<Type> d2 = default(SpanLike<int>).GetType; Func<string> d3 = default(Span<int>).ToString; } } "; CSharpCompilation comp = CreateCompilationWithMscorlibAndSpan(text); comp.VerifyEmitDiagnostics( // (10,48): error CS0123: No overload for 'GetHashCode' matches delegate 'Func<int>' // Func<int> d0 = default(TypedReference).GetHashCode; Diagnostic(ErrorCode.ERR_MethDelegateMismatch, "GetHashCode").WithArguments("GetHashCode", "System.Func<int>").WithLocation(10, 48), // (13,43): error CS0123: No overload for 'GetHashCode' matches delegate 'Func<int>' // Func<int> d1 = default(Span<int>).GetHashCode; Diagnostic(ErrorCode.ERR_MethDelegateMismatch, "GetHashCode").WithArguments("GetHashCode", "System.Func<int>").WithLocation(13, 43), // (15,48): error CS0123: No overload for 'GetType' matches delegate 'Func<Type>' // Func<Type> d2 = default(SpanLike<int>).GetType; Diagnostic(ErrorCode.ERR_MethDelegateMismatch, "GetType").WithArguments("GetType", "System.Func<System.Type>").WithLocation(15, 48), // (17,46): error CS0123: No overload for 'ToString' matches delegate 'Func<string>' // Func<string> d3 = default(Span<int>).ToString; Diagnostic(ErrorCode.ERR_MethDelegateMismatch, "ToString").WithArguments("ToString", "System.Func<string>").WithLocation(17, 46) ); } [Fact] public void RefSpanDetectBoxing_NoRef() { string spanSource = @" namespace System { public struct Span<T> { } public struct ReadOnlySpan<T> { } }"; var reference = CreateEmptyCompilation( spanSource, references: new List<MetadataReference>() { MscorlibRef_v4_0_30316_17626, SystemCoreRef, CSharpRef }, options: TestOptions.ReleaseDll); reference.VerifyDiagnostics(); var text = @" class Program { static void Main() { object x = new System.Span<int>(); object y = new System.ReadOnlySpan<byte>(); } } "; var comp = CreateEmptyCompilation( text, references: new List<MetadataReference>() { MscorlibRef_v4_0_30316_17626, SystemCoreRef, CSharpRef, reference.EmitToImageReference() }, options: TestOptions.ReleaseExe); comp.VerifyDiagnostics(); } [Fact] public void RefSpanDetectBoxing_Ref() { string spanSource = @" namespace System { public ref struct Span<T> { } public ref struct ReadOnlySpan<T> { } }"; var reference = CreateEmptyCompilation( spanSource, references: new List<MetadataReference>() { MscorlibRef_v4_0_30316_17626, SystemCoreRef, CSharpRef }, options: TestOptions.ReleaseDll); reference.VerifyDiagnostics(); var text = @" class Program { static void Main() { object x = new System.Span<int>(); object y = new System.ReadOnlySpan<byte>(); } } "; var comp = CreateEmptyCompilation( text, references: new List<MetadataReference>() { MscorlibRef_v4_0_30316_17626, SystemCoreRef, CSharpRef, reference.EmitToImageReference() }, options: TestOptions.ReleaseExe); comp.VerifyDiagnostics( // (6,20): error CS0029: Cannot implicitly convert type 'System.Span<int>' to 'object' // object x = new System.Span<int>(); Diagnostic(ErrorCode.ERR_NoImplicitConv, "new System.Span<int>()").WithArguments("System.Span<int>", "object").WithLocation(6, 20), // (7,20): error CS0029: Cannot implicitly convert type 'System.ReadOnlySpan<byte>' to 'object' // object y = new System.ReadOnlySpan<byte>(); Diagnostic(ErrorCode.ERR_NoImplicitConv, "new System.ReadOnlySpan<byte>()").WithArguments("System.ReadOnlySpan<byte>", "object").WithLocation(7, 20)); } [Fact] public void CannotUseNonRefSpan() { string spanSource = @" namespace System { public struct Span<T> { unsafe public Span(void* pointer, int length) { } } }"; var reference = CreateEmptyCompilation( spanSource, references: new List<MetadataReference>() { MscorlibRef_v4_0_30316_17626, SystemCoreRef, CSharpRef }, options: TestOptions.UnsafeReleaseDll); reference.VerifyDiagnostics(); var text = @" using System; class Program { static void Main() { Span<int> x = stackalloc int [10]; } } "; var comp = CreateEmptyCompilation( text, references: new List<MetadataReference>() { MscorlibRef_v4_0_30316_17626, SystemCoreRef, CSharpRef, reference.EmitToImageReference() }, options: TestOptions.ReleaseExe); comp.VerifyDiagnostics( // (7,23): error CS8346: Conversion of a stackalloc expression of type 'int' to type 'Span<int>' is not possible. // Span<int> x = stackalloc int [10]; Diagnostic(ErrorCode.ERR_StackAllocConversionNotPossible, "stackalloc int [10]").WithArguments("int", "System.Span<int>").WithLocation(7, 23)); } [Fact] public void CannotUseNonStructSpan() { string spanSource = @" namespace System { public class Span<T> { unsafe public Span(void* pointer, int length) { } } }"; var reference = CreateEmptyCompilation( spanSource, references: new List<MetadataReference>() { MscorlibRef_v4_0_30316_17626, SystemCoreRef, CSharpRef }, options: TestOptions.UnsafeReleaseDll); reference.VerifyDiagnostics(); var text = @" using System; class Program { static void Main() { Span<int> x = stackalloc int [10]; } } "; var comp = CreateEmptyCompilation( text, references: new List<MetadataReference>() { MscorlibRef_v4_0_30316_17626, SystemCoreRef, CSharpRef, reference.EmitToImageReference() }, options: TestOptions.ReleaseExe); comp.VerifyDiagnostics( // (7,23): error CS8346: Conversion of a stackalloc expression of type 'int' to type 'Span<int>' is not possible. // Span<int> x = stackalloc int [10]; Diagnostic(ErrorCode.ERR_StackAllocConversionNotPossible, "stackalloc int [10]").WithArguments("int", "System.Span<int>").WithLocation(7, 23)); } [Fact] [WorkItem(23627, "https://github.com/dotnet/roslyn/issues/23627")] public void CreateVariableFromRefStructFieldInNonRefStruct() { var code = @" public ref struct Point { } class Program { public Point field1 = new Point(); public static Point field2 = new Point(); void Check() { var temp1 = field1; var temp2 = field2; } }"; CreateCompilation(code).VerifyDiagnostics( // (8,19): error CS8345: Field or auto-implemented property cannot be of type 'Point' unless it is an instance member of a ref struct. // public static Point field2 = new Point(); Diagnostic(ErrorCode.ERR_FieldAutoPropCantBeByRefLike, "Point").WithArguments("Point").WithLocation(8, 19), // (7,12): error CS8345: Field or auto-implemented property cannot be of type 'Point' unless it is an instance member of a ref struct. // public Point field1 = new Point(); Diagnostic(ErrorCode.ERR_FieldAutoPropCantBeByRefLike, "Point").WithArguments("Point").WithLocation(7, 12)); } [Fact] [WorkItem(23627, "https://github.com/dotnet/roslyn/issues/23627")] public void CreateVariableFromRefStructFieldInRefStruct() { var code = @" public ref struct Point { } ref struct Program { public static Point field1; public static Point field2 = new Point(); public Program(Point p) { field1 = p; } void Check() { var temp1 = field1; var temp2 = field2; } }"; CreateCompilation(code).VerifyDiagnostics( // (8,19): error CS8345: Field or auto-implemented property cannot be of type 'Point' unless it is an instance member of a ref struct. // public static Point field2 = new Point(); Diagnostic(ErrorCode.ERR_FieldAutoPropCantBeByRefLike, "Point").WithArguments("Point").WithLocation(8, 19), // (7,19): error CS8345: Field or auto-implemented property cannot be of type 'Point' unless it is an instance member of a ref struct. // public static Point field1; Diagnostic(ErrorCode.ERR_FieldAutoPropCantBeByRefLike, "Point").WithArguments("Point").WithLocation(7, 19)); } [Fact] [WorkItem(24627, "https://github.com/dotnet/roslyn/issues/24627")] public void ArgMixingBogusInstanceCall() { var comp = CreateCompilationWithMscorlibAndSpan(@" class Program { ref struct S1 { public void Test(int x) => throw null; public int this[int x] => throw null; public S1(S1 x, int y) => throw null; } static void Main() { // these are all errors, we should not be doing escape analysis on them. S1.Test(1); var x = S1[1]; var y = new S1(S1, 1); } }"); comp.VerifyDiagnostics( // (14,9): error CS0120: An object reference is required for the non-static field, method, or property 'Program.S1.Test(int)' // S1.Test(1); Diagnostic(ErrorCode.ERR_ObjectRequired, "S1.Test").WithArguments("Program.S1.Test(int)").WithLocation(14, 9), // (15,17): error CS0119: 'Program.S1' is a type, which is not valid in the given context // var x = S1[1]; Diagnostic(ErrorCode.ERR_BadSKunknown, "S1").WithArguments("Program.S1", "type").WithLocation(15, 17), // (16,24): error CS0119: 'Program.S1' is a type, which is not valid in the given context // var y = new S1(S1, 1); Diagnostic(ErrorCode.ERR_BadSKunknown, "S1").WithArguments("Program.S1", "type").WithLocation(16, 24) ); } [WorkItem(27874, "https://github.com/dotnet/roslyn/issues/27874")] [Theory] [InlineData(LanguageVersion.CSharp10)] [InlineData(LanguageVersion.CSharp11)] public void PassingSpansToLocals_EscapeScope_01(LanguageVersion languageVersion) { var source = @"using System; class C { static void Main() { Span<int> x = stackalloc int [10]; Console.WriteLine(M1(ref x).Length); Console.WriteLine(M2(ref x).Length); } static ref Span<int> M1(ref Span<int> x) { ref Span<int> q = ref x; return ref q; } static ref Span<int> M2(ref Span<int> x) { return ref x; } }"; var comp = CreateCompilationWithMscorlibAndSpan(source, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion), options: TestOptions.ReleaseExe); CompileAndVerify(comp, verify: Verification.Fails, expectedOutput: @" 10 10"); } [WorkItem(27874, "https://github.com/dotnet/roslyn/issues/27874")] [Theory] [InlineData(LanguageVersion.CSharp10)] [InlineData(LanguageVersion.CSharp11)] public void PassingSpansToLocals_EscapeScope_02(LanguageVersion languageVersion) { var source = @"using System; class C { static void Main() { Span<int> x = stackalloc int [10]; Console.WriteLine(M1(ref x).Length); Console.WriteLine(M2(ref x).Length); } static ref Span<int> M1(ref Span<int> x) { ref Span<int> q = ref x; return ref q; } static ref Span<int> M2(ref Span<int> x) { return ref x; } }"; var comp = CreateCompilationWithMscorlibAndSpan(source, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion), options: TestOptions.ReleaseExe); CompileAndVerify(comp, verify: Verification.Fails, expectedOutput: @" 10 10"); } [Fact] [WorkItem(27357, "https://github.com/dotnet/roslyn/issues/27357")] public void PassingSpansToInParameters_Methods() { CompileAndVerify(CreateCompilationWithMscorlibAndSpan(@" using System; class C { static void Main() { Span<int> s1 = stackalloc int[1]; M1(s1); } static void M1(Span<int> s1) { Span<int> s2 = stackalloc int[2]; M2(s1, s2); M2(s2, s1); M2(s1, in s2); M2(s2, in s1); M2(x: s1, y: in s2); M2(x: s2, y: in s1); M2(y: in s2, x: s1); M2(y: in s1, x: s2); } static void M2(Span<int> x, in Span<int> y) { Console.WriteLine(x.Length + "" - "" + y.Length); } }", options: TestOptions.ReleaseExe), verify: Verification.Fails, expectedOutput: @" 1 - 2 2 - 1 1 - 2 2 - 1 1 - 2 2 - 1 1 - 2 2 - 1"); } [Fact] [WorkItem(27357, "https://github.com/dotnet/roslyn/issues/27357")] public void PassingSpansToInParameters_Indexers() { CompileAndVerify(CreateCompilationWithMscorlibAndSpan(@" using System; class C { static void Main() { Span<int> s1 = stackalloc int[1]; M1(s1); } static void M1(Span<int> s1) { var obj = new C(); Span<int> s2 = stackalloc int[2]; Console.WriteLine(obj[s1, s2]); Console.WriteLine(obj[s2, s1]); Console.WriteLine(obj[s1, in s2]); Console.WriteLine(obj[s2, in s1]); Console.WriteLine(obj[x: s1, y: in s2]); Console.WriteLine(obj[x: s2, y: in s1]); Console.WriteLine(obj[y: in s2, x: s1]); Console.WriteLine(obj[y: in s1, x: s2]); } string this[Span<int> x, in Span<int> y] => x.Length + "" - "" + y.Length; }", options: TestOptions.ReleaseExe), verify: Verification.Fails, expectedOutput: @" 1 - 2 2 - 1 1 - 2 2 - 1 1 - 2 2 - 1 1 - 2 2 - 1"); } [Theory] [InlineData(LanguageVersion.CSharp10)] [InlineData(LanguageVersion.CSharp11)] [WorkItem(27357, "https://github.com/dotnet/roslyn/issues/27357")] public void PassingSpansToParameters_Errors(LanguageVersion languageVersion) { var comp = CreateCompilationWithMscorlibAndSpan(@" using System; class C { static void Main() { Span<int> s1 = stackalloc int[1]; M1(s1); } static void M1(Span<int> s1) { var obj = new C(); Span<int> s2 = stackalloc int[2]; M2(ref s1, out s2); // one M2(ref s2, out s1); // two M2(ref s1, out s2); // three M2(ref s2, out s1); // four M2(y: out s2, x: ref s1); // five M2(y: out s1, x: ref s2); // six M2(ref s1, out s1); // okay M2(ref s2, out s2); // okay } static void M2(scoped ref Span<int> x, out Span<int> y) { y = default; } }", parseOptions: TestOptions.RegularDefault.WithLanguageVersion(languageVersion)); if (languageVersion == LanguageVersion.CSharp10) { // In C# 7.2 the input to an `out` parameter can escape which means several // of the tests are errors due to stack copying to escape comp.VerifyDiagnostics( // (16,9): error CS8350: This combination of arguments to 'C.M2(scoped ref Span<int>, out Span<int>)' is disallowed because it may expose variables referenced by parameter 'y' outside of their declaration scope // M2(ref s1, out s2); // one Diagnostic(ErrorCode.ERR_CallArgMixing, "M2(ref s1, out s2)").WithArguments("C.M2(scoped ref System.Span<int>, out System.Span<int>)", "y").WithLocation(16, 9), // (16,24): error CS8352: Cannot use variable 's2' in this context because it may expose referenced variables outside of their declaration scope // M2(ref s1, out s2); // one Diagnostic(ErrorCode.ERR_EscapeVariable, "s2").WithArguments("s2").WithLocation(16, 24), // (17,9): error CS8350: This combination of arguments to 'C.M2(scoped ref Span<int>, out Span<int>)' is disallowed because it may expose variables referenced by parameter 'x' outside of their declaration scope // M2(ref s2, out s1); // two Diagnostic(ErrorCode.ERR_CallArgMixing, "M2(ref s2, out s1)").WithArguments("C.M2(scoped ref System.Span<int>, out System.Span<int>)", "x").WithLocation(17, 9), // (17,16): error CS8352: Cannot use variable 's2' in this context because it may expose referenced variables outside of their declaration scope // M2(ref s2, out s1); // two Diagnostic(ErrorCode.ERR_EscapeVariable, "s2").WithArguments("s2").WithLocation(17, 16), // (19,9): error CS8350: This combination of arguments to 'C.M2(scoped ref Span<int>, out Span<int>)' is disallowed because it may expose variables referenced by parameter 'y' outside of their declaration scope // M2(ref s1, out s2); // three Diagnostic(ErrorCode.ERR_CallArgMixing, "M2(ref s1, out s2)").WithArguments("C.M2(scoped ref System.Span<int>, out System.Span<int>)", "y").WithLocation(19, 9), // (19,24): error CS8352: Cannot use variable 's2' in this context because it may expose referenced variables outside of their declaration scope // M2(ref s1, out s2); // three Diagnostic(ErrorCode.ERR_EscapeVariable, "s2").WithArguments("s2").WithLocation(19, 24), // (20,9): error CS8350: This combination of arguments to 'C.M2(scoped ref Span<int>, out Span<int>)' is disallowed because it may expose variables referenced by parameter 'x' outside of their declaration scope // M2(ref s2, out s1); // four Diagnostic(ErrorCode.ERR_CallArgMixing, "M2(ref s2, out s1)").WithArguments("C.M2(scoped ref System.Span<int>, out System.Span<int>)", "x").WithLocation(20, 9), // (20,16): error CS8352: Cannot use variable 's2' in this context because it may expose referenced variables outside of their declaration scope // M2(ref s2, out s1); // four Diagnostic(ErrorCode.ERR_EscapeVariable, "s2").WithArguments("s2").WithLocation(20, 16), // (22,9): error CS8350: This combination of arguments to 'C.M2(scoped ref Span<int>, out Span<int>)' is disallowed because it may expose variables referenced by parameter 'y' outside of their declaration scope // M2(y: out s2, x: ref s1); // five Diagnostic(ErrorCode.ERR_CallArgMixing, "M2(y: out s2, x: ref s1)").WithArguments("C.M2(scoped ref System.Span<int>, out System.Span<int>)", "y").WithLocation(22, 9), // (22,19): error CS8352: Cannot use variable 's2' in this context because it may expose referenced variables outside of their declaration scope // M2(y: out s2, x: ref s1); // five Diagnostic(ErrorCode.ERR_EscapeVariable, "s2").WithArguments("s2").WithLocation(22, 19), // (23,9): error CS8350: This combination of arguments to 'C.M2(scoped ref Span<int>, out Span<int>)' is disallowed because it may expose variables referenced by parameter 'x' outside of their declaration scope // M2(y: out s1, x: ref s2); // six Diagnostic(ErrorCode.ERR_CallArgMixing, "M2(y: out s1, x: ref s2)").WithArguments("C.M2(scoped ref System.Span<int>, out System.Span<int>)", "x").WithLocation(23, 9), // (23,30): error CS8352: Cannot use variable 's2' in this context because it may expose referenced variables outside of their declaration scope // M2(y: out s1, x: ref s2); // six Diagnostic(ErrorCode.ERR_EscapeVariable, "s2").WithArguments("s2").WithLocation(23, 30), // (29,20): error CS8936: Feature 'ref fields' is not available in C# 10.0. Please use language version 11.0 or greater. // static void M2(scoped ref Span<int> x, out Span<int> y) Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "scoped").WithArguments("ref fields", "11.0").WithLocation(29, 20)); } else { comp.VerifyDiagnostics( // (17,9): error CS8350: This combination of arguments to 'C.M2(scoped ref Span<int>, out Span<int>)' is disallowed because it may expose variables referenced by parameter 'x' outside of their declaration scope // M2(ref s2, out s1); // two Diagnostic(ErrorCode.ERR_CallArgMixing, "M2(ref s2, out s1)").WithArguments("C.M2(scoped ref System.Span<int>, out System.Span<int>)", "x").WithLocation(17, 9), // (17,16): error CS8352: Cannot use variable 's2' in this context because it may expose referenced variables outside of their declaration scope // M2(ref s2, out s1); // two Diagnostic(ErrorCode.ERR_EscapeVariable, "s2").WithArguments("s2").WithLocation(17, 16), // (20,9): error CS8350: This combination of arguments to 'C.M2(scoped ref Span<int>, out Span<int>)' is disallowed because it may expose variables referenced by parameter 'x' outside of their declaration scope // M2(ref s2, out s1); // four Diagnostic(ErrorCode.ERR_CallArgMixing, "M2(ref s2, out s1)").WithArguments("C.M2(scoped ref System.Span<int>, out System.Span<int>)", "x").WithLocation(20, 9), // (20,16): error CS8352: Cannot use variable 's2' in this context because it may expose referenced variables outside of their declaration scope // M2(ref s2, out s1); // four Diagnostic(ErrorCode.ERR_EscapeVariable, "s2").WithArguments("s2").WithLocation(20, 16), // (23,9): error CS8350: This combination of arguments to 'C.M2(scoped ref Span<int>, out Span<int>)' is disallowed because it may expose variables referenced by parameter 'x' outside of their declaration scope // M2(y: out s1, x: ref s2); // six Diagnostic(ErrorCode.ERR_CallArgMixing, "M2(y: out s1, x: ref s2)").WithArguments("C.M2(scoped ref System.Span<int>, out System.Span<int>)", "x").WithLocation(23, 9), // (23,30): error CS8352: Cannot use variable 's2' in this context because it may expose referenced variables outside of their declaration scope // M2(y: out s1, x: ref s2); // six Diagnostic(ErrorCode.ERR_EscapeVariable, "s2").WithArguments("s2").WithLocation(23, 30)); } } [Fact] [WorkItem(27357, "https://github.com/dotnet/roslyn/issues/27357")] public void PassingSpansToParameters_Errors_Arglist() { CreateCompilationWithMscorlibAndSpan(@" using System; class C { static void Main() { Span<int> s1 = stackalloc int[1]; M1(s1); } static void M1(Span<int> s1) { var obj = new C(); Span<int> s2 = stackalloc int[2]; M2(__arglist(ref s1, ref s2)); // one M2(__arglist(ref s2, ref s1)); // two } static void M2(__arglist) { } }").VerifyDiagnostics( // (16,34): error CS8352: Cannot use variable 's2' in this context because it may expose referenced variables outside of their declaration scope // M2(__arglist(ref s1, ref s2)); // one Diagnostic(ErrorCode.ERR_EscapeVariable, "s2").WithArguments("s2").WithLocation(16, 34), // (16,9): error CS8350: This combination of arguments to 'C.M2(__arglist)' is disallowed because it may expose variables referenced by parameter '__arglist' outside of their declaration scope // M2(__arglist(ref s1, ref s2)); // one Diagnostic(ErrorCode.ERR_CallArgMixing, "M2(__arglist(ref s1, ref s2))").WithArguments("C.M2(__arglist)", "__arglist").WithLocation(16, 9), // (17,26): error CS8352: Cannot use variable 's2' in this context because it may expose referenced variables outside of their declaration scope // M2(__arglist(ref s2, ref s1)); // two Diagnostic(ErrorCode.ERR_EscapeVariable, "s2").WithArguments("s2").WithLocation(17, 26), // (17,9): error CS8350: This combination of arguments to 'C.M2(__arglist)' is disallowed because it may expose variables referenced by parameter '__arglist' outside of their declaration scope // M2(__arglist(ref s2, ref s1)); // two Diagnostic(ErrorCode.ERR_CallArgMixing, "M2(__arglist(ref s2, ref s1))").WithArguments("C.M2(__arglist)", "__arglist").WithLocation(17, 9)); } [Fact] [WorkItem(44588, "https://github.com/dotnet/roslyn/issues/44588")] public void SwitchDefaultLocalInitialization_01() { var source = @" using System; struct Struct2 { public static ReadOnlySpan<T> GetSpan1<T>(int x) { return x switch { 0 => default, _ => default, }; } public static ReadOnlySpan<T> GetSpan2<T>(int x) { ReadOnlySpan<T> span; span = x switch { 0 => default, _ => default, }; return span; } public static ReadOnlySpan<T> GetSpan3<T>(int x) { ReadOnlySpan<T> span = x switch { 0 => default, _ => default, }; return span; } public static ReadOnlySpan<T> GetSpan4<T>(int x) { ReadOnlySpan<T> span = default; return span; } }"; CreateCompilationWithMscorlibAndSpan(source).VerifyDiagnostics( ); } [Fact] [WorkItem(44588, "https://github.com/dotnet/roslyn/issues/44588")] public void SwitchDefaultLocalInitialization_02() { var source = @" using System; struct Struct2 { public static Span<byte> GetSpan1(int x) { return x switch { 0 => stackalloc byte[10], // 1 _ => default, }; } public static Span<byte> GetSpan2(int x) { Span<byte> span; span = x switch { 0 => stackalloc byte[10], // 2 _ => default, }; return span; } public static Span<byte> GetSpan3(int x) { Span<byte> span = x switch { 0 => stackalloc byte[10], _ => default, }; return span; // 3 } public static Span<byte> GetSpan4(int x) { Span<byte> span = stackalloc byte[10]; return span; // 4 } }"; CreateCompilationWithMscorlibAndSpan(source).VerifyDiagnostics( // (10,18): error CS8353: A result of a stackalloc expression of type 'Span<byte>' cannot be used in this context because it may be exposed outside of the containing method // 0 => stackalloc byte[10], // 1 Diagnostic(ErrorCode.ERR_EscapeStackAlloc, "stackalloc byte[10]").WithArguments("System.Span<byte>").WithLocation(10, 18), // (21,18): error CS8353: A result of a stackalloc expression of type 'Span<byte>' cannot be used in this context because it may be exposed outside of the containing method // 0 => stackalloc byte[10], // 2 Diagnostic(ErrorCode.ERR_EscapeStackAlloc, "stackalloc byte[10]").WithArguments("System.Span<byte>").WithLocation(21, 18), // (36,16): error CS8352: Cannot use variable 'span' in this context because it may expose referenced variables outside of their declaration scope // return span; // 3 Diagnostic(ErrorCode.ERR_EscapeVariable, "span").WithArguments("span").WithLocation(36, 16), // (43,16): error CS8352: Cannot use variable 'span' in this context because it may expose referenced variables outside of their declaration scope // return span; // 4 Diagnostic(ErrorCode.ERR_EscapeVariable, "span").WithArguments("span").WithLocation(43, 16) ); } [Fact] [WorkItem(39663, "https://github.com/dotnet/roslyn/issues/39663")] public void AssignToDiscard_01() { var text = @" using System; class Program { static void Main() { _ = Test(stackalloc int[5]); System.Console.WriteLine(""Done""); } static Span<int> Test(Span<int> items) => items; } "; CSharpCompilation comp = CreateCompilationWithMscorlibAndSpan(text, options: TestOptions.DebugExe); CompileAndVerify(comp, verify: Verification.Fails, expectedOutput: "Done").VerifyDiagnostics(); } [Fact] [WorkItem(39663, "https://github.com/dotnet/roslyn/issues/39663")] public void AssignToDiscard_02() { var text = @" using System; class Program { static int[] _array = new int[] {}; static void Main() { _ = Test; System.Console.WriteLine(""Done""); } static Span<int> Test => _array; } "; CSharpCompilation comp = CreateCompilationWithMscorlibAndSpan(text, options: TestOptions.DebugExe); // ILVerify: Return type is ByRef, TypedReference, ArgHandle, or ArgIterator. CompileAndVerify(comp, expectedOutput: "Done", verify: Verification.FailsILVerify).VerifyDiagnostics(); } [Fact] [WorkItem(39663, "https://github.com/dotnet/roslyn/issues/39663")] public void AssignToDiscard_03() { var text = @" using System; class Program { static void Main() { var l = Test(stackalloc int[5]); _ = l; System.Console.WriteLine(""Done""); } static Span<int> Test(Span<int> items) => items; } "; CSharpCompilation comp = CreateCompilationWithMscorlibAndSpan(text, options: TestOptions.DebugExe); CompileAndVerify(comp, verify: Verification.Fails, expectedOutput: "Done").VerifyDiagnostics(); } [Fact] [WorkItem(39663, "https://github.com/dotnet/roslyn/issues/39663")] public void AssignToDiscard_04() { var text = @" using System; class Program { static void Main() { var l = Test(stackalloc int[5]); { int i = 0; _ = l; i++; } System.Console.WriteLine(""Done""); } static Span<int> Test(Span<int> items) => items; } "; CSharpCompilation comp = CreateCompilationWithMscorlibAndSpan(text, options: TestOptions.DebugExe); CompileAndVerify(comp, verify: Verification.Fails, expectedOutput: "Done").VerifyDiagnostics(); } [Fact] [WorkItem(39663, "https://github.com/dotnet/roslyn/issues/39663")] public void AssignToDiscard_05() { var text = @" using System; class Program { static void Main() { Test(stackalloc int[5]); System.Console.WriteLine(""Done""); } static Span<int> Test(Span<int> items) => items; } "; CSharpCompilation comp = CreateCompilationWithMscorlibAndSpan(text, options: TestOptions.DebugExe); CompileAndVerify(comp, verify: Verification.Fails, expectedOutput: "Done").VerifyDiagnostics(); } } }