diff --git a/src/libraries/System.Private.CoreLib/src/System/Threading/Tasks/Task.cs b/src/libraries/System.Private.CoreLib/src/System/Threading/Tasks/Task.cs index 22621aa85e26b7..cae33611d5d98c 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Threading/Tasks/Task.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Threading/Tasks/Task.cs @@ -5297,13 +5297,15 @@ public static unsafe Task FromResult(TResult result) } else if (!RuntimeHelpers.IsReferenceOrContainsReferences()) { - // For other value types, we special-case default(TResult) if we can easily compare bit patterns to default/0. + // For other value types, we special-case default(TResult) if we can efficiently compare bit patterns to default/0, + // which means any value type that's 1, 2, 4, 8, or 16 bytes in size and that doesn't contain references. // We don't need to go through the equality operator of the TResult because we cached a task for default(TResult), // so we only need to confirm that this TResult has the same bits as default(TResult). if ((sizeof(TResult) == sizeof(byte) && *(byte*)&result == default(byte)) || (sizeof(TResult) == sizeof(ushort) && *(ushort*)&result == default(ushort)) || (sizeof(TResult) == sizeof(uint) && *(uint*)&result == default) || - (sizeof(TResult) == sizeof(ulong) && *(ulong*)&result == default)) + (sizeof(TResult) == sizeof(ulong) && *(ulong*)&result == default) || + (sizeof(TResult) == sizeof(UInt128) && *(UInt128*)&result == default)) { return Task.s_defaultResultTask; } diff --git a/src/libraries/System.Threading.Tasks/tests/System.Runtime.CompilerServices/AsyncTaskMethodBuilderTests.cs b/src/libraries/System.Threading.Tasks/tests/System.Runtime.CompilerServices/AsyncTaskMethodBuilderTests.cs index acbd9bdc600f78..2ef2b23ce935d2 100644 --- a/src/libraries/System.Threading.Tasks/tests/System.Runtime.CompilerServices/AsyncTaskMethodBuilderTests.cs +++ b/src/libraries/System.Threading.Tasks/tests/System.Runtime.CompilerServices/AsyncTaskMethodBuilderTests.cs @@ -377,7 +377,7 @@ public static void TaskMethodBuilderInt32_UsesCompletedCache(int result, bool sh [Fact] public static void TaskMethodBuilderDecimal_DoesntUseCompletedCache() { - TaskMethodBuilderT_UsesCompletedCache(0m, shouldBeCached: false); + TaskMethodBuilderT_UsesCompletedCache(default(decimal), shouldBeCached: true); TaskMethodBuilderT_UsesCompletedCache(0.0m, shouldBeCached: false); TaskMethodBuilderT_UsesCompletedCache(42m, shouldBeCached: false); } diff --git a/src/libraries/System.Threading.Tasks/tests/Task/TaskRtTests.cs b/src/libraries/System.Threading.Tasks/tests/Task/TaskRtTests.cs index b2f69398af4414..f89f6d60d87305 100644 --- a/src/libraries/System.Threading.Tasks/tests/Task/TaskRtTests.cs +++ b/src/libraries/System.Threading.Tasks/tests/Task/TaskRtTests.cs @@ -470,70 +470,45 @@ public static void FromResult_KnownResults_Cached() // Cached - foreach (bool result in new[] { false, true }) - { - Assert.Same(Task.FromResult(result), Task.FromResult(result)); - Assert.Equal(result, Task.FromResult(result).Result); - } + AssertCached(false); + AssertCached(true); for (int i = -1; i <= 8; i++) { - Assert.Same(Task.FromResult(i), Task.FromResult(i)); - Assert.Equal(i, Task.FromResult(i).Result); + AssertCached(i); } - Assert.Same(Task.FromResult('\0'), Task.FromResult('\0')); - Assert.Equal('\0', Task.FromResult('\0').Result); - - Assert.Same(Task.FromResult((byte)0), Task.FromResult((byte)0)); - Assert.Equal(0, Task.FromResult((byte)0).Result); - - Assert.Same(Task.FromResult((ushort)0), Task.FromResult((ushort)0)); - Assert.Equal(0, Task.FromResult((ushort)0).Result); - - Assert.Same(Task.FromResult((uint)0), Task.FromResult((uint)0)); - Assert.Equal(0u, Task.FromResult((uint)0).Result); - - Assert.Same(Task.FromResult((ulong)0), Task.FromResult((ulong)0)); - Assert.Equal(0ul, Task.FromResult((ulong)0).Result); - - Assert.Same(Task.FromResult((sbyte)0), Task.FromResult((sbyte)0)); - Assert.Equal(0, Task.FromResult((sbyte)0).Result); - - Assert.Same(Task.FromResult((short)0), Task.FromResult((short)0)); - Assert.Equal(0, Task.FromResult((short)0).Result); - - Assert.Same(Task.FromResult((long)0), Task.FromResult((long)0)); - Assert.Equal(0, Task.FromResult((long)0).Result); - - Assert.Same(Task.FromResult(IntPtr.Zero), Task.FromResult(IntPtr.Zero)); - Assert.Equal(IntPtr.Zero, Task.FromResult(IntPtr.Zero).Result); - - Assert.Same(Task.FromResult(UIntPtr.Zero), Task.FromResult(UIntPtr.Zero)); - Assert.Equal(UIntPtr.Zero, Task.FromResult(UIntPtr.Zero).Result); - - Assert.Same(Task.FromResult((Half)default), Task.FromResult((Half)default)); - Assert.Equal((Half)default, Task.FromResult((Half)default).Result); - - Assert.Same(Task.FromResult((float)default), Task.FromResult((float)default)); - Assert.Equal((float)default, Task.FromResult((float)default).Result); - - Assert.Same(Task.FromResult((double)default), Task.FromResult((double)default)); - Assert.Equal((double)default, Task.FromResult((double)default).Result); - - Assert.Same(Task.FromResult((TimeSpan)default), Task.FromResult((TimeSpan)default)); - Assert.Equal((TimeSpan)default, Task.FromResult((TimeSpan)default).Result); - - Assert.Same(Task.FromResult((DateTime)default), Task.FromResult((DateTime)default)); - Assert.Equal((DateTime)default, Task.FromResult((DateTime)default).Result); - - Assert.Same(Task.FromResult((object)null), Task.FromResult((object)null)); - Assert.Null(Task.FromResult((object)null).Result); - - Assert.Same(Task.FromResult((string)null), Task.FromResult((string)null)); - Assert.Null(Task.FromResult((string)null).Result); + AssertCached(); + AssertCached(); + AssertCached(); + AssertCached(); + AssertCached(); + AssertCached(); + AssertCached(); + AssertCached(); + AssertCached(); + AssertCached(); + AssertCached(); + AssertCached(); + AssertCached(); + AssertCached(); + AssertCached(); + AssertCached(); + AssertCached(); + AssertCached(); + AssertCached(); + AssertCached(); + AssertCached(); + AssertCached(); + AssertCached(); + + static void AssertCached(T value = default) + { + Assert.Same(Task.FromResult(value), Task.FromResult(value)); + Assert.Equal(value, Task.FromResult(value).Result); + } - // Not cached + // Not currently cached foreach (int i in new[] { -2, 9, int.MinValue, int.MaxValue }) { @@ -541,11 +516,11 @@ public static void FromResult_KnownResults_Cached() Assert.Equal(i, Task.FromResult(i).Result); } + // Should never return the same task + Assert.NotSame(Task.FromResult((double)(+0.0)), Task.FromResult((double)(-0.0))); Assert.NotSame(Task.FromResult((float)(+0.0)), Task.FromResult((float)(-0.0))); Assert.NotSame(Task.FromResult((Half)(+0.0)), Task.FromResult((Half)(-0.0))); - - Assert.NotSame(Task.FromResult((decimal)default), Task.FromResult((decimal)default)); } [Fact]