mirror of https://github.com/icsharpcode/ILSpy.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
492 lines
9.2 KiB
492 lines
9.2 KiB
using System; |
|
using System.Diagnostics.CodeAnalysis; |
|
|
|
namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty |
|
{ |
|
internal struct Buffer |
|
{ |
|
private int value; |
|
|
|
[UnscopedRef] |
|
public ref int GetRef() |
|
{ |
|
return ref value; |
|
} |
|
} |
|
|
|
internal ref struct Holder |
|
{ |
|
public Span<int> Inner; |
|
|
|
public void Set(Span<int> inner) |
|
{ |
|
Inner = inner; |
|
} |
|
|
|
public readonly void ReadonlyUse(Span<int> inner) |
|
{ |
|
_ = inner.Length; |
|
} |
|
} |
|
|
|
internal static class HolderExtensions |
|
{ |
|
public static void SetExtension(this ref Holder holder, Span<int> inner) |
|
{ |
|
holder.Inner = inner; |
|
} |
|
|
|
public static void ReadonlyExtension(this in Holder holder, Span<int> inner) |
|
{ |
|
_ = inner.Length; |
|
} |
|
} |
|
|
|
internal class LifetimeTests |
|
{ |
|
private static int staticField; |
|
|
|
public Span<int> CreateWithoutCapture(scoped ref int value) |
|
{ |
|
// Okay: value is not captured |
|
return new Span<int>(ref staticField); |
|
} |
|
|
|
public Span<int> CreateAndCapture(ref int value) |
|
{ |
|
// Okay: value Rule 3 specifies that the safe-to-escape be limited to the ref-safe-to-escape |
|
// of the ref argument. That is the *calling method* for value hence this is not allowed. |
|
return new Span<int>(ref value); |
|
} |
|
|
|
public Span<int> ScopedRefSpan(scoped ref Span<int> span) |
|
{ |
|
return span; |
|
} |
|
|
|
public Span<int> ScopedSpan(scoped Span<int> span) |
|
{ |
|
return default; |
|
} |
|
|
|
public void OutSpan(out Span<int> span) |
|
{ |
|
span = default; |
|
} |
|
|
|
public void CaptureIntoRef(ref Holder holder, Span<int> inner) |
|
{ |
|
holder.Inner = inner; |
|
} |
|
|
|
public void CaptureIntoOut(out Holder holder, Span<int> inner) |
|
{ |
|
holder = default; |
|
holder.Inner = inner; |
|
} |
|
|
|
public void CaptureRefIntoOut(out Holder holder, ref int value) |
|
{ |
|
holder = default; |
|
holder.Inner = new Span<int>(ref value); |
|
} |
|
|
|
public ref Holder Identity(ref Holder holder) |
|
{ |
|
return ref holder; |
|
} |
|
|
|
public Span<int> CaptureOut([UnscopedRef] out int value) |
|
{ |
|
value = 0; |
|
return new Span<int>(ref value); |
|
} |
|
|
|
public Span<int> NoCaptureOut(out int value) |
|
{ |
|
value = 0; |
|
return default; |
|
} |
|
|
|
public Span<int> Identity(Span<int> span) |
|
{ |
|
return span; |
|
} |
|
|
|
public void Calls() |
|
{ |
|
int value = 0; |
|
scoped Span<int> span = CreateWithoutCapture(ref value); |
|
span = CreateAndCapture(ref value); |
|
span = ScopedRefSpan(ref span); |
|
span = ScopedSpan(span); |
|
OutSpan(out span); |
|
} |
|
|
|
public int ReassignScopedRefToLocal(bool b, ref int x) |
|
{ |
|
int num = 42; |
|
scoped ref int reference = ref x; |
|
if (b) |
|
{ |
|
reference = ref num; |
|
} |
|
return reference; |
|
} |
|
|
|
public int ReassignScopedSpanFromOut(bool b) |
|
{ |
|
int value = 0; |
|
scoped Span<int> span = default; |
|
if (b) |
|
{ |
|
span = CaptureOut(out value); |
|
} |
|
return span[0] + value; |
|
} |
|
|
|
public int ImplicitScopedOutDoesNotCapture() |
|
{ |
|
Span<int> span = default; |
|
span = NoCaptureOut(out var value); |
|
Console.WriteLine(span.Length); |
|
return span.Length + value; |
|
} |
|
|
|
public int ReassignScopedSpanFromReceiver(bool b) |
|
{ |
|
UnscopedRefStruct unscopedRefStruct = default; |
|
scoped Span<int> span = default; |
|
if (b) |
|
{ |
|
span = unscopedRefStruct.AsSpan(); |
|
} |
|
return span[0]; |
|
} |
|
|
|
public int ReassignScopedSpanFromRefParameter(bool b, ref int value) |
|
{ |
|
scoped Span<int> span = default; |
|
if (b) |
|
{ |
|
span = CreateAndCapture(ref value); |
|
} |
|
return span[0]; |
|
} |
|
|
|
public int ReassignScopedSpanFromStackAlloc(bool b) |
|
{ |
|
scoped Span<int> span = default; |
|
if (b) |
|
{ |
|
span = stackalloc int[1]; |
|
} |
|
return span[0]; |
|
} |
|
|
|
public int ReassignScopedSpanFromScopedValue(bool b, scoped Span<int> value) |
|
{ |
|
scoped Span<int> span = default; |
|
if (b) |
|
{ |
|
span = value; |
|
} |
|
return span[0]; |
|
} |
|
|
|
public int ReassignScopedSpanFromNestedCall(bool b) |
|
{ |
|
int value = 0; |
|
scoped Span<int> span = default; |
|
if (b) |
|
{ |
|
span = Identity(CreateAndCapture(ref value)); |
|
} |
|
return span[0]; |
|
} |
|
|
|
public int ReassignScopedSpanFromLocalCopy(bool b) |
|
{ |
|
Span<int> span = stackalloc int[1]; |
|
scoped Span<int> span2 = default; |
|
if (b) |
|
{ |
|
span2 = span; |
|
} |
|
return span2[0]; |
|
} |
|
|
|
public int ReassignScopedSpanFromScopedRefValue(bool b) |
|
{ |
|
Span<int> span = stackalloc int[1]; |
|
scoped Span<int> span2 = default; |
|
if (b) |
|
{ |
|
span2 = ScopedRefSpan(ref span); |
|
} |
|
return span2[0]; |
|
} |
|
|
|
public int NarrowInitializerDoesNotNeedScoped(bool b) |
|
{ |
|
int num = 1; |
|
int num2 = 2; |
|
ref int reference = ref num; |
|
if (b) |
|
{ |
|
reference = ref num2; |
|
} |
|
return reference; |
|
} |
|
|
|
public int NarrowThenWideDoesNotNeedScoped(bool b, ref int value) |
|
{ |
|
int num = 1; |
|
ref int reference = ref num; |
|
if (b) |
|
{ |
|
reference = ref value; |
|
} |
|
return reference; |
|
} |
|
|
|
public int ClassParameterReceiverDoesNotNarrow(SpanProvider provider, bool b) |
|
{ |
|
Span<int> span = default; |
|
if (b) |
|
{ |
|
span = provider.GetBuffer(); |
|
} |
|
return span.Length; |
|
} |
|
|
|
public int ClassLocalReceiverDoesNotNarrow(bool b) |
|
{ |
|
SpanProvider spanProvider = new SpanProvider(); |
|
Span<int> span = default; |
|
if (b) |
|
{ |
|
span = spanProvider.GetBuffer(); |
|
} |
|
return span.Length; |
|
} |
|
|
|
public ref int PlainStructReceiverDoesNotForceScoped(bool b, ref Buffer buffer, ref int other) |
|
{ |
|
ref int result = ref buffer.GetRef(); |
|
if (b) |
|
{ |
|
result = ref other; |
|
} |
|
return ref result; |
|
} |
|
|
|
public int FieldStoreRequiresScoped() |
|
{ |
|
scoped Holder holder = default; |
|
Span<int> inner = stackalloc int[4]; |
|
holder.Inner = inner; |
|
return holder.Inner.Length; |
|
} |
|
|
|
public int ReceiverCallRequiresScoped() |
|
{ |
|
scoped Holder holder = default; |
|
Span<int> inner = stackalloc int[4]; |
|
holder.Set(inner); |
|
return holder.Inner.Length; |
|
} |
|
|
|
public int ExtensionReceiverCallRequiresScoped() |
|
{ |
|
scoped Holder holder = default; |
|
Span<int> inner = stackalloc int[4]; |
|
holder.SetExtension(inner); |
|
return holder.Inner.Length; |
|
} |
|
|
|
public int RefArgumentCallRequiresScoped() |
|
{ |
|
scoped Holder holder = default; |
|
Span<int> inner = stackalloc int[4]; |
|
CaptureIntoRef(ref holder, inner); |
|
return holder.Inner.Length; |
|
} |
|
|
|
public int OutArgumentCallRequiresScoped() |
|
{ |
|
scoped Holder holder = default; |
|
Span<int> inner = stackalloc int[4]; |
|
CaptureIntoOut(out holder, inner); |
|
return holder.Inner.Length; |
|
} |
|
|
|
public int OutArgumentCapturesRefRequiresScoped() |
|
{ |
|
int value = 0; |
|
scoped Holder holder = default; |
|
CaptureRefIntoOut(out holder, ref value); |
|
return holder.Inner[0]; |
|
} |
|
|
|
public Holder RefArgumentWideValueDoesNotRequireScoped(Span<int> wide) |
|
{ |
|
Holder holder = default; |
|
CaptureIntoRef(ref holder, wide); |
|
return holder; |
|
} |
|
|
|
public Holder OutArgumentWideValueDoesNotRequireScoped(Span<int> wide) |
|
{ |
|
Holder holder = default; |
|
CaptureIntoOut(out holder, wide); |
|
return holder; |
|
} |
|
|
|
public int RefReturnFieldStoreRequiresScoped() |
|
{ |
|
scoped Holder holder = default; |
|
Span<int> inner = stackalloc int[4]; |
|
Identity(ref holder).Inner = inner; |
|
return holder.Inner.Length; |
|
} |
|
|
|
public Holder RefReturnFieldStoreWideValueDoesNotRequireScoped(Span<int> wide) |
|
{ |
|
Holder holder = default; |
|
Identity(ref holder).Inner = wide; |
|
return holder; |
|
} |
|
|
|
public Holder ReadonlyReceiverDoesNotRequireScoped(bool b) |
|
{ |
|
Holder result = default; |
|
if (b) |
|
{ |
|
Span<int> inner = stackalloc int[4]; |
|
result.ReadonlyUse(inner); |
|
} |
|
return result; |
|
} |
|
|
|
public Holder ReadonlyExtensionReceiverDoesNotRequireScoped(bool b) |
|
{ |
|
Holder holder = default; |
|
if (b) |
|
{ |
|
Span<int> inner = stackalloc int[4]; |
|
holder.ReadonlyExtension(inner); |
|
} |
|
return holder; |
|
} |
|
|
|
public ReadOnlyHolder ReadonlyRefStructReceiverDoesNotRequireScoped(bool b, Span<int> wide) |
|
{ |
|
ReadOnlyHolder result = new ReadOnlyHolder(wide); |
|
if (b) |
|
{ |
|
Span<int> other = stackalloc int[1]; |
|
result.Compare(other); |
|
} |
|
return result; |
|
} |
|
|
|
public int TryInitThenReassign(bool condition, Span<int> wide) |
|
{ |
|
scoped Span<int> span; |
|
try |
|
{ |
|
span = stackalloc int[4]; |
|
} |
|
finally |
|
{ |
|
Console.WriteLine("cleanup"); |
|
} |
|
if (condition) |
|
{ |
|
span = wide; |
|
} |
|
return span[0]; |
|
} |
|
|
|
} |
|
|
|
internal readonly ref struct ReadOnlyHolder(Span<int> inner) |
|
{ |
|
private readonly Span<int> inner = inner; |
|
|
|
public void Compare(Span<int> other) |
|
{ |
|
_ = inner.Length; |
|
_ = other.Length; |
|
} |
|
} |
|
|
|
internal ref struct RefFields |
|
{ |
|
public ref int Field0; |
|
public ref readonly int Field1; |
|
public readonly ref int Field2; |
|
public readonly ref readonly int Field3; |
|
|
|
public int PropertyAccessingRefFieldByValue { |
|
get { |
|
return Field0; |
|
} |
|
set { |
|
Field0 = value; |
|
} |
|
} |
|
|
|
public ref int PropertyReturningRefFieldByReference => ref Field0; |
|
|
|
public void Uses(int[] array) |
|
{ |
|
Field1 = ref array[0]; |
|
Field2 = array[0]; |
|
} |
|
|
|
public void ReadonlyLocal() |
|
{ |
|
ref readonly int field = ref Field1; |
|
Console.WriteLine("No inlining"); |
|
field.ToString(); |
|
} |
|
|
|
public RefFields(ref int v) |
|
{ |
|
Field0 = ref v; |
|
Field1 = ref v; |
|
Field2 = ref v; |
|
Field3 = ref v; |
|
} |
|
} |
|
|
|
internal sealed class SpanProvider |
|
{ |
|
public Span<int> GetBuffer() |
|
{ |
|
return default; |
|
} |
|
} |
|
|
|
internal ref struct UnscopedRefStruct |
|
{ |
|
private int val; |
|
|
|
[UnscopedRef] |
|
public ref int ByRefProperty => ref val; |
|
|
|
[UnscopedRef] |
|
public ref int ByRefAccess() |
|
{ |
|
return ref val; |
|
} |
|
|
|
[UnscopedRef] |
|
public Span<int> AsSpan() |
|
{ |
|
return new Span<int>(ref val); |
|
} |
|
} |
|
}
|
|
|