net10.0: Support MethodImpl.Async
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)
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
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.
@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)
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.
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)
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?
Can use the LanguageFeature mechanism and be in preview (and likely stay in preview)
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