Broken Async Method Builder

CSharp · Console

/Program.cs

#nullable enable
namespace NoItDoesNotGetCalled
{
    using System;
    using System.Runtime.CompilerServices;
    using System.Threading.Tasks;

    [AsyncMethodBuilder(typeof(CustomAwaitableAsyncMethodBuilder<>))]
    public readonly struct CustomAwaitable<T>
    {
        readonly ValueTask<T> _valueTask;

        public CustomAwaitable(ValueTask<T> valueTask)
        {
            _valueTask = valueTask;
        }

        public ValueTaskAwaiter<T> GetAwaiter() => _valueTask.GetAwaiter();
    }

    public struct CustomAwaitableAsyncMethodBuilder<T>
    {
        public CustomAwaitable<T> Task => default;

        public void AwaitOnCompleted<TAwaiter, TStateMachine>(
            ref TAwaiter awaiter,
            ref TStateMachine stateMachine)
            where TAwaiter : INotifyCompletion
            where TStateMachine : IAsyncStateMachine =>
            awaiter.OnCompleted(stateMachine.MoveNext);

        public void AwaitUnsafeOnCompleted<TAwaiter, TStateMachine>(
            ref TAwaiter awaiter,
            ref TStateMachine stateMachine)
            where TAwaiter : ICriticalNotifyCompletion
            where TStateMachine : IAsyncStateMachine =>
            awaiter.UnsafeOnCompleted(stateMachine.MoveNext);

        public static CustomAwaitableAsyncMethodBuilder<T> Create() => default;

        public void SetException(Exception exception) {}

        public void SetResult(T result) {}

        public void SetStateMachine(IAsyncStateMachine stateMachine)
        {
            Console.WriteLine("Yet this doesn't happen :(");
        }

        public void Start<TStateMachine>(ref TStateMachine stateMachine)
            where TStateMachine : IAsyncStateMachine
        {
            if (typeof(TStateMachine).IsValueType)
            {
                Console.WriteLine("See? Here's a state machine that's implemented as a struct!");
            }
            stateMachine.MoveNext();
        }
    }

    public class Program
    {
        public static async Task Main()
        {
			async CustomAwaitable<object?> GetValueAsync()
            {
                await Task.CompletedTask;
                return null;
            }
            await GetValueAsync();
        }
    }
}
;