From 1e374512a1385a8721888c1fc87ec67b275ae7a8 Mon Sep 17 00:00:00 2001 From: Marc Zwart Date: Tue, 20 Jan 2026 00:57:03 +0100 Subject: [PATCH 1/3] add failing test for completed task of long marshalling --- .../JavaScript/JSExportTest.cs | 26 +++++++++++++++++++ .../JavaScript/JavaScriptTestHelper.cs | 12 ++++++++- 2 files changed, 37 insertions(+), 1 deletion(-) diff --git a/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System/Runtime/InteropServices/JavaScript/JSExportTest.cs b/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System/Runtime/InteropServices/JavaScript/JSExportTest.cs index 7e6364265b335b..4eae0ab9cb10c8 100644 --- a/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System/Runtime/InteropServices/JavaScript/JSExportTest.cs +++ b/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System/Runtime/InteropServices/JavaScript/JSExportTest.cs @@ -390,6 +390,32 @@ public async Task JsExportTaskOfInt(int value) //GC.Collect(); } + [Theory] + [MemberData(nameof(MarshalBigInt64Cases))] + public async Task JsExportTaskOfLong(long value) + { + TaskCompletionSource tcs = new TaskCompletionSource(); + var res = JavaScriptTestHelper.invoke1_TaskOfLong(tcs.Task, nameof(JavaScriptTestHelper.AwaitTaskOfInt64)); + tcs.SetResult(value); // incompleted task marshalls promise and resolves on completion + await Task.Yield(); + var rr = await res; + await Task.Yield(); + Assert.Equal(value, rr); + } + + [Theory] + [MemberData(nameof(MarshalBigInt64Cases))] + public async Task JsExportCompletedTaskOfLong(long value) + { + TaskCompletionSource tcs = new TaskCompletionSource(); + tcs.SetResult(value); // completed task marshalls value immediately + var res = JavaScriptTestHelper.invoke1_TaskOfLong(tcs.Task, nameof(JavaScriptTestHelper.AwaitTaskOfInt64)); + await Task.Yield(); + var rr = await res; + await Task.Yield(); + Assert.Equal(value, rr); + } + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotWasmThreadingSupported))] public void JsExportCallback_FunctionIntInt() { diff --git a/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System/Runtime/InteropServices/JavaScript/JavaScriptTestHelper.cs b/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System/Runtime/InteropServices/JavaScript/JavaScriptTestHelper.cs index 26b81d5bf52273..c064839d530677 100644 --- a/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System/Runtime/InteropServices/JavaScript/JavaScriptTestHelper.cs +++ b/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System/Runtime/InteropServices/JavaScript/JavaScriptTestHelper.cs @@ -441,7 +441,9 @@ public static Exception EchoException([JSMarshalAs] Exception arg1 [JSImport("invoke1", "JavaScriptTestHelper")] [return: JSMarshalAs>] internal static partial Task invoke1_TaskOfInt([JSMarshalAs>] Task value, [JSMarshalAs] string name); - + [JSImport("invoke1", "JavaScriptTestHelper")] + [return: JSMarshalAs>] + internal static partial Task invoke1_TaskOfLong([JSMarshalAs>] Task value, [JSMarshalAs] string name); [JSImport("returnResolvedPromise", "JavaScriptTestHelper")] internal static partial Task ReturnResolvedPromise(); @@ -462,6 +464,14 @@ public static async Task AwaitTaskOfObject([JSMarshalAs>] + public static async Task AwaitTaskOfInt64([JSMarshalAs>] Task arg1) + { + var res = await arg1; + return res; + } + #endregion #region Action + Func From 52e64bc5e0d17fd03fcf83d635abc49fe61bfe7c Mon Sep 17 00:00:00 2001 From: Marc Zwart Date: Tue, 20 Jan 2026 00:58:22 +0100 Subject: [PATCH 2/3] use marshaller provided by codegen in completed task path --- .../JavaScript/Marshaling/JSMarshalerArgument.Task.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libraries/System.Runtime.InteropServices.JavaScript/src/System/Runtime/InteropServices/JavaScript/Marshaling/JSMarshalerArgument.Task.cs b/src/libraries/System.Runtime.InteropServices.JavaScript/src/System/Runtime/InteropServices/JavaScript/Marshaling/JSMarshalerArgument.Task.cs index 38a8e20487571c..910a6f472e9c00 100644 --- a/src/libraries/System.Runtime.InteropServices.JavaScript/src/System/Runtime/InteropServices/JavaScript/Marshaling/JSMarshalerArgument.Task.cs +++ b/src/libraries/System.Runtime.InteropServices.JavaScript/src/System/Runtime/InteropServices/JavaScript/Marshaling/JSMarshalerArgument.Task.cs @@ -357,7 +357,7 @@ public void ToJS(Task? value, ArgumentToJSCallback marshaler) else { T result = task.Result; - ToJS(result); + marshaler(ref this, result); slot.ElementType = slot.Type; slot.Type = MarshalerType.TaskResolved; return; From 3d1966dc587fee8bf327307c5fc5d41561d64667 Mon Sep 17 00:00:00 2001 From: Pavel Savara Date: Tue, 20 Jan 2026 12:47:21 +0100 Subject: [PATCH 3/3] nit --- .../System/Runtime/InteropServices/JavaScript/JSExportTest.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System/Runtime/InteropServices/JavaScript/JSExportTest.cs b/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System/Runtime/InteropServices/JavaScript/JSExportTest.cs index 4eae0ab9cb10c8..f6e7e99abd310b 100644 --- a/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System/Runtime/InteropServices/JavaScript/JSExportTest.cs +++ b/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System/Runtime/InteropServices/JavaScript/JSExportTest.cs @@ -396,7 +396,7 @@ public async Task JsExportTaskOfLong(long value) { TaskCompletionSource tcs = new TaskCompletionSource(); var res = JavaScriptTestHelper.invoke1_TaskOfLong(tcs.Task, nameof(JavaScriptTestHelper.AwaitTaskOfInt64)); - tcs.SetResult(value); // incompleted task marshalls promise and resolves on completion + tcs.SetResult(value); // unresolved task marshalls promise and resolves on completion await Task.Yield(); var rr = await res; await Task.Yield();