Skip to content

Commit 66aeb98

Browse files
authored
Alternative fix for RuntimeHelpers.GetSubArray AOT compatibility warning (#95296)
* Revert "Simplify RuntimeHelpers.GetSubArray (#66011)" This reverts commit ca3c95b. * Alternative fix for the AOT compatibility warning * Add test
1 parent f735fdf commit 66aeb98

File tree

2 files changed

+35
-9
lines changed

2 files changed

+35
-9
lines changed

src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/RuntimeHelpers.cs

+22-8
Original file line numberDiff line numberDiff line change
@@ -27,18 +27,32 @@ public static T[] GetSubArray<T>(T[] array, Range range)
2727

2828
(int offset, int length) = range.GetOffsetAndLength(array.Length);
2929

30-
if (length == 0)
30+
T[] dest;
31+
32+
if (typeof(T[]) == array.GetType())
3133
{
32-
return Array.Empty<T>();
34+
// We know the type of the array to be exactly T[].
35+
36+
if (length == 0)
37+
{
38+
return Array.Empty<T>();
39+
}
40+
41+
dest = new T[length];
3342
}
43+
else
44+
{
45+
// The array is actually a U[] where U:T. We'll make sure to create
46+
// an array of the exact same backing type. The cast to T[] will
47+
// never fail.
3448

35-
T[] dest = new T[length];
49+
dest = Unsafe.As<T[]>(Array.CreateInstanceFromArrayType(array.GetType(), length));
50+
}
3651

37-
// Due to array variance, it's possible that the incoming array is
38-
// actually of type U[], where U:T; or that an int[] <-> uint[] or
39-
// similar cast has occurred. In any case, since it's always legal
40-
// to reinterpret U as T in this scenario (but not necessarily the
41-
// other way around), we can use Buffer.Memmove here.
52+
// In either case, the newly-allocated array is the exact same type as the
53+
// original incoming array. It's safe for us to Buffer.Memmove the contents
54+
// from the source array to the destination array, otherwise the contents
55+
// wouldn't have been valid for the source array in the first place.
4256

4357
Buffer.Memmove(
4458
ref MemoryMarshal.GetArrayDataReference(dest),

src/libraries/System.Runtime/tests/System.Runtime.Tests/System/Runtime/CompilerServices/RuntimeHelpersTests.cs

+13-1
Original file line numberDiff line numberDiff line change
@@ -348,7 +348,7 @@ public static void IsReferenceOrContainsReferences()
348348
}
349349

350350
[Fact]
351-
public static void ArrayRangeHelperTest()
351+
public static void ArrayGetSubArrayTest()
352352
{
353353
int[] a = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
354354
Range range = Range.All;
@@ -361,6 +361,18 @@ public static void ArrayRangeHelperTest()
361361
Assert.Throws<ArgumentOutOfRangeException>(() => { int [] array = RuntimeHelpers.GetSubArray(a, range); });
362362
}
363363

364+
[Fact]
365+
public static void ArrayGetSubArrayCoVarianceTest()
366+
{
367+
object[] arr = new string[10];
368+
object[] slice = RuntimeHelpers.GetSubArray<object>(arr, new Range(Index.FromStart(1), Index.FromEnd(2)));
369+
Assert.IsType<string[]>(slice);
370+
371+
uint[] arr2 = (uint[])(object)new int[10];
372+
uint[] slice2 = RuntimeHelpers.GetSubArray<uint>(arr2, new Range(Index.FromStart(1), Index.FromEnd(2)));
373+
Assert.IsType<int[]>(slice2);
374+
}
375+
364376
[Fact]
365377
[SkipOnMono("Not presently implemented on Mono")]
366378
public static void AllocateTypeAssociatedMemoryInvalidArguments()

0 commit comments

Comments
 (0)