fsharp icon indicating copy to clipboard operation
fsharp copied to clipboard

net10.0: Support MethodImpl.Async

Open TheAngryByrd opened this issue 2 months ago • 8 comments

Context

👋 .NET 10 is bringing support for Runtime-Async. I started playing around with it in an IcedTasks PR. However, I noticed some of benchmarks being off considerably. One of the requirements is having MethodImplOptions.Async set. I manually added the atttribute, but it doesn't get written to the IL.

Repro steps

Provide the steps required to reproduce the problem:

    [<MethodImpl(MethodImplOptions.Async)>]
    let fsharp_tenBindAsync_TaskBuilderRuntime () =
        IcedTasks.Polyfill.TasksRuntime.TaskBuilder.task {
            do! taskYield ()
            return 100
        }

see that the compiled DLL doesn't contain it in the IL/decompiled c#


    public static Task<int> fsharp_tenBindAsync_TaskBuilderRuntime()
    {
      YieldAwaitable.YieldAwaiter awaiter1 = Task.Yield().GetAwaiter();
      if (!awaiter1.IsCompleted)
        AsyncHelpers.UnsafeAwaitAwaiter<YieldAwaitable.YieldAwaiter>(awaiter1);
      awaiter1.GetResult();
      ValueTaskAwaiter<int> awaiter11 = ValueTask.FromResult<int>(100).GetAwaiter();
      if (!awaiter11.IsCompleted)
        AsyncHelpers.UnsafeAwaitAwaiter<ValueTaskAwaiter<int>>(awaiter11);
      return Task.FromResult<int>(awaiter11.GetResult());
    }

ilprint seems to need to have detection and output for it done. However, the current detection relies on MethodImpl being in netstandard2.0, since this is part of net10.0, there would have to be some compat layer here.

https://github.com/dotnet/fsharp/blob/6ec56c25f451e887185fd918b83891249b00357a/src/Compiler/AbstractIL/ilprint.fs#L717-L730


Secondly, as a separate discussion point. Having people manually add this attribute would be extremely inconvenient. What options do you see as possible for a CE to add attributes to the methods that get written out? (We can move to a separate discussion if needed)

Expected behavior

MethodImpl is preserved

Actual behavior

MethodImpl is not preserved

Known workarounds

Hand editing the IL?

Related information

Provide any related information (optional):

  • Operating system
  • .NET Runtime kind (.NET Core, .NET Framework, Mono)
  • Editing Tools (e.g. Visual Studio Version, Visual Studio)

TheAngryByrd avatar Nov 06 '25 03:11 TheAngryByrd

Possibly this should be a separate issue (though it could be addressed at the same time) is that the int16 overload for MethodImpl appears not to be supported at all. Looking at the decompiled C#, the C# version always applies MethodImplOptions.AggressiveInlining and F# ignores the int16 version.

using System.Runtime.CompilerServices;
public static class MyModule
{
    [MethodImpl(256)]
    public static int add(int x, int y)
    {
        return x + y;
    }

    [MethodImpl(MethodImplOptions.AggressiveInlining)]

    public static int add2(int x, int y)
    {
        return x + y;
    }
}
open System.Runtime.CompilerServices

module MyModule =

    [<MethodImpl(256s)>]
    let add x y = x + y

    [<MethodImpl(MethodImplOptions.AggressiveInlining)>]
    let add2 x y = x + y

roboz0r avatar Nov 06 '25 03:11 roboz0r

We fully appreciate the experimentation you are doing.

One idea would be a compiler intrinsic in fslib which the compiler would detect and turn into ILMethod metadata at ilxgen time. It would locate the parent IL method, would that meet the needs?

I would likely want to keep this undocumented and created for the sole purpose of runtime async experiments, until things stabilize and an overall approach for F# via a new suggestion is discussed.


Od: roboz0r @.> Odesláno: čtvrtek 6. listopadu 2025 4:35 Komu: dotnet/fsharp @.> Kopie: Subscribed @.***> Předmět: Re: [dotnet/fsharp] net10.0: Support MethodImpl.Async (Issue #19056)

Possibly this should be a separate issue (though it could be addressed at the same time) is that the int16 overload for MethodImpl appears not to be supported at all. Looking at the decompiled C#, the C# version always applies MethodImplOptions.AggressiveInlining and F# ignores the int16 version.

using System.Runtime.CompilerServices; public static class MyModule { [MethodImpl(256)] public static int add(int x, int y) { return x + y; }

[MethodImpl(MethodImplOptions.AggressiveInlining)]

public static int add2(int x, int y)
{
    return x + y;
}

}

open System.Runtime.CompilerServices

module MyModule =

[<MethodImpl(256s)>]
let add x y = x + y

[<MethodImpl(MethodImplOptions.AggressiveInlining)>]
let add2 x y = x + y

— Reply to this email directly, view it on GitHubhttps://github.com/dotnet/fsharp/issues/19056#issuecomment-3494745457 or unsubscribehttps://github.com/notifications/unsubscribe-auth/ALDDFXZAJZGITULX7JAJ54T33K6XRBFKMF2HI4TJMJ2XIZLTS2BKK5TBNR2WLJDUOJ2WLJDOMFWWLO3UNBZGKYLEL5YGC4TUNFRWS4DBNZ2F6YLDORUXM2LUPGBKK5TBNR2WLJDUOJ2WLJDOMFWWLLTXMF2GG2C7MFRXI2LWNF2HTAVFOZQWY5LFUVUXG43VMWSG4YLNMWVXI2DSMVQWIX3UPFYGLAVFOZQWY5LFU44TCMBWGYYDJJDOMFWWLKDBMN2G64S7NFSIFJLWMFWHKZNJGE3DINZYHE3DANVENZQW2ZNJNBQXGX3MMFRGK3ECUV3GC3DVMWVDINBVHEYTOMBTGQ4KI3TBNVS2S2DBONPWYYLCMVWKY43VMJVGKY3UL52HS4DFVREXG43VMVBW63LNMVXHJJTUN5YGSY3TSKBKI5DZOBS2U4TFOBXXG2LUN5ZHTJLWMFWHKZNIGI4TANBYHA4TDAVEOR4XAZNFNFZXG5LFUV3GC3DVMWVDGNJZGM3TEMJWGQYKO5DSNFTWOZLSUZRXEZLBORSQ. You are receiving this email because you are subscribed to this thread.

Triage notifications on the go with GitHub Mobile for iOShttps://apps.apple.com/app/apple-store/id1477376905?ct=notification-email&mt=8&pt=524675 or Androidhttps://play.google.com/store/apps/details?id=com.github.android&referrer=utm_campaign%3Dnotification-email%26utm_medium%3Demail%26utm_source%3Dgithub.

T-Gro avatar Nov 06 '25 07:11 T-Gro

@TheAngryByrd :

Does it make sense to solve the explicit manual declaration in isolation, or is that of lesser help and you would really want the automatic CE mechanism ?

Definitely happy to brainstorm the alternatives (another idea would be a defined CE-keyword, like add_attributes, which would copy over attributes from the builder's method declaration over to the user-space owning IL method)

T-Gro avatar Nov 10 '25 12:11 T-Gro

Ive got some local fork thats writing the IL if you add the attribute manually, but its supposed to be only generated by the compiler (C# disallows you writing it manually).

I was playing with the idea of writing the attribute whenever a method has “AsyncHelpler.Await” or any of the other overloads. But im definitely open to other options that you think make sense.

TheAngryByrd avatar Nov 10 '25 13:11 TheAngryByrd

I would prefer a smaller non-specialized addition to the compiler now, just to enable experimentation within libraries (since compiler is by nature slow to change due to release cycle) and be ready to changes/additions in the runtime implementation.

Once the feature stabilizes, a compiled detection based on method calls at IL codegen time is OK (pending if/how/if at all do anything for Fable to be aware of it)

T-Gro avatar Nov 10 '25 14:11 T-Gro

Ok I'll submit the small change to let people use the Attribute for now.

Should we hide it behind a feature flag since we'll probably want to disallow people from using it directly in the future?

TheAngryByrd avatar Nov 10 '25 15:11 TheAngryByrd

Can use the LanguageFeature mechanism and be in preview (and likely stay in preview)

T-Gro avatar Nov 10 '25 15:11 T-Gro

This was the bare minimum I got to this weekend but I still need to do more verifications/testing + FeatureFlag

https://github.com/dotnet/fsharp/pull/19065

TheAngryByrd avatar Nov 10 '25 15:11 TheAngryByrd