|
// 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(
// (11,15): error CS8352: Cannot use variable 's1' in this context because it may expose referenced variables outside of their declaration scope
// s2 = (s1 = s2);
Diagnostic(ErrorCode.ERR_EscapeVariable, "s1 = s2").WithArguments("s1").WithLocation(11, 15));
}
[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)
);
}
[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();
}
}
}
|