Interop: a params overload is chosen by the array's element type, and a failing element declines instead of throwing (#3764) - #3782
Merged
Conversation
… a failing element declines instead of throwing Backport of sebastienros#3764 to 4.x. A `params` call bundles its trailing arguments into one `JsArray` before overload resolution runs, so `InteropHelper.CalculateMethodParameterScore` rated three candidates differing only in their element type - `CDecimal[]`, `CInteger[]`, `CLong[]` - with one rule, "is an array, wants an array", that answered a flat 2 for every one of them. The element type was never consulted, the converter probe below that rule (the sebastienros#3407 fix) was never reached, and declaration order decided. Where the first-declared candidate happened to be convertible it answered silently and wrongly; where it was not, the conversion's `InvalidCastException` left through the embedder's `Evaluate`. It escaped because of the second defect. The composite branches of `DefaultTypeConverter.TryConvert` - a `List<T>` or `Collection<T>` item, a `T[]` element, a target dictionary's value, a member of a POCO built from a dictionary - converted their parts through the public, throwing `Convert`, ignoring the `propagateException` flag their own frame had been called with. So a method documented as returning false threw, which is not something the candidate loop in `MethodInfoFunction.Call` can move on from: it tries candidates in score order and declines its way to the next, and an exception ends the call rather than the candidate. Both are fixed together, because fixing the first by asking the converter per element throws until the second is fixed. - `TryConvertPart` routes all five composite sites through the flag their frame was given. It mirrors `Convert` - the virtual `TryConvert` first, so a subclass override still answers for the parts - so behaviour under `propagateException: true` is unchanged. - `CalculateParameterTypeScore` is the type-level core of the parameter score, so an element with no `ParameterInfo` of its own can be scored by the same rules. An array parameter now scores its base 2 plus its *worst* element, up to eight of them, and returns -1 on the first element that cannot bind at all. Element types any `JsValue` is assignable to - `object`, `JsValue` - are carved out and keep the flat base, or `params object[]` and `params JsValue[]` would rank below the scalar overload beside them. Deliberately out of scope: `MethodDescriptor.Call`'s `TypeReference` constructor lane keeps its throwing `Convert` and gets no retry loop - correct selection is what repairs it, exactly as sebastienros#3407 repaired that lane - and an empty JS array against several `params T[]` overloads stays ambiguous and keeps today's answer. Pinned in `Jint.Tests.PublicInterface/HostArrayElementOverloadTests.cs` and `Jint.Tests/Runtime/CompositeConversionDeclineTests.cs`, which fail 8/11 and 5/11 respectively on unfixed 4.x, on both net472 and net10.0. Closes sebastienros#3754 on 4.x Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LfyCDDqtkhyWVEFHKWhZfu
This was referenced Sep 9, 2026
PatrickSt1991
pushed a commit
to Apps2Samsung/Apps2Samsung
that referenced
this pull request
Sep 14, 2026
Updated [Avalonia](https://github.com/AvaloniaUI/Avalonia/) from 11.3.20 to 11.3.22. <details> <summary>Release notes</summary> _Sourced from [Avalonia's releases](https://github.com/AvaloniaUI/Avalonia//releases)._ No release notes found for this version range. Commits viewable in [compare view](https://github.com/AvaloniaUI/Avalonia//commits). </details> Updated [Avalonia.Desktop](https://github.com/AvaloniaUI/Avalonia/) from 11.3.20 to 11.3.22. <details> <summary>Release notes</summary> _Sourced from [Avalonia.Desktop's releases](https://github.com/AvaloniaUI/Avalonia//releases)._ No release notes found for this version range. Commits viewable in [compare view](https://github.com/AvaloniaUI/Avalonia//commits). </details> Updated [Avalonia.Diagnostics](https://github.com/AvaloniaUI/Avalonia/) from 11.3.20 to 11.3.22. <details> <summary>Release notes</summary> _Sourced from [Avalonia.Diagnostics's releases](https://github.com/AvaloniaUI/Avalonia//releases)._ No release notes found for this version range. Commits viewable in [compare view](https://github.com/AvaloniaUI/Avalonia//commits). </details> Updated [Avalonia.Fonts.Inter](https://github.com/AvaloniaUI/Avalonia/) from 11.3.20 to 11.3.22. <details> <summary>Release notes</summary> _Sourced from [Avalonia.Fonts.Inter's releases](https://github.com/AvaloniaUI/Avalonia//releases)._ No release notes found for this version range. Commits viewable in [compare view](https://github.com/AvaloniaUI/Avalonia//commits). </details> Updated [Avalonia.Themes.Fluent](https://github.com/AvaloniaUI/Avalonia/) from 11.3.20 to 11.3.22. <details> <summary>Release notes</summary> _Sourced from [Avalonia.Themes.Fluent's releases](https://github.com/AvaloniaUI/Avalonia//releases)._ No release notes found for this version range. Commits viewable in [compare view](https://github.com/AvaloniaUI/Avalonia//commits). </details> Updated [Jint](https://github.com/sebastienros/jint) from 4.16.1 to 4.16.2. <details> <summary>Release notes</summary> _Sourced from [Jint's releases](https://github.com/sebastienros/jint/releases)._ ## 4.16.2 Jint 4.16.2 is a maintenance release from the `4.x` branch: **correctness and conformance fixes backported from `main`, and nothing that changes an existing API or an existing default.** If you are on 4.16.1 it is a drop-in update — every public signature is the one 4.16.0 shipped, on all five target frameworks, and the per-framework snapshots in `Jint.Tests.PublicInterface/Verify/` are unchanged. `main` remains 5.0.0 development; what is coming there is recorded as it lands in [`docs/v5-migration.md`](https://github.com/sebastienros/jint/blob/main/docs/v5-migration.md). ### Highlights **Failures that used to end the process, or never end.** A native error raised while a call's arguments are being evaluated is propagated instead of leaving an empty value behind, which on 4.16.1 could recurse until the process died — `decodeURIComponent` on a malformed sequence was enough (#4009). Native recursion and the forwarding paths through bound functions and proxies are guarded so a deep native chain raises a catchable error (#4007). A module graph too deep to link raises an error the host can catch instead of overflowing the stack (#3548). Temporal and Intl parsing cannot throw an uncatchable `RegexMatchTimeoutException` because the machine was busy (#3543), a Temporal difference past a calendar's range raises `RangeError` instead of spinning forever (#3555), and the process-wide Intl culture cache and Temporal zone cache are read-only and bounded, with a rejected zone no longer remembered — closing a script-driven unbounded growth (#3546). **Generators and built-ins, step by step.** A `yield*` delegation reached again by a loop both re-delegates and keeps its place: `countdown(3)` in a loop no longer hangs, and a delegating generator no longer returns the memoized first result (#3545). `Array.prototype.map` and `slice` hand a `@@species` constructor the length `ToLength` produced, and a non-callable `map` argument is a `TypeError` (#3547). A trailing NUL pads neither a numeric string nor an array index (#3552). A removed property slot is a tombstone rather than a free slot to reuse, so enumeration order survives a delete-and-readd (#3318), and `LengthOfArrayLike` no longer clamps through a `uint` overload (#3328). **Interop that answers for the right engine.** Two engines in one process no longer decide each other's conversions and operators (#3559), a host type converter's answer stays with the engine whose converter gave it (#3563), and a value the host registers on a `ShadowRealm` — and the members its wrapper builds eagerly — belong to that realm (#3557). Realm construction state is restored after nesting or a failure (#4008). Overload selection is by the arguments in hand: an operator overload is chosen that way (#3611), a `params` overload is chosen by the array's element type with a failing element declining rather than throwing (#3782), an overload the argument cannot bind to is not a match, and a host operator that throws reports what it threw (#3554). An index on a wrapped host collection is one property however it is spelled, and a member filter that hides the indexer hides it (#3562); a read-only host collection refuses a write with a JavaScript `TypeError` rather than the CLR's `NotSupportedException` (#3556). **Internationalization and Temporal.** The Persian calendar extends into proleptic years on its 33-year cycle, so the ends of Temporal's range land in the right Persian year (#4006); a calendar that counts Gregorian months writes their names (#3612); and a `-u-` extension carrying more than one key is read whole (#3613). **Errors.** Only a string-valued `stack` counts as a pre-existing stack when a `JavaScriptException` is built, so an accessor or non-string `stack` on a thrown object no longer breaks error reporting (#3677, reported by @jeske). Every change was verified failing-first against the unfixed branch on both .NET Framework and .NET 10, and the release was gated on a paired SunSpider and Dromaeo comparison against 4.16.1 on an idle machine: no row regressed outside run-to-run noise, most run 1–4 % faster. ## What's Changed * Backport: a removed property slot is a tombstone, not a free slot to reuse (#3273) by @lahma in sebastienros/jint#3318 * Backport: LengthOfArrayLike, delete the uint overload rather than clamp it (#3248) by @lahma in sebastienros/jint#3328 * Temporal and Intl parsing cannot fail because the machine was busy (#3486) by @lahma in sebastienros/jint#3543 * Backport: the process-wide Intl culture cache and Temporal zone cache are read-only and bounded, and a rejected zone is not remembered by @lahma in sebastienros/jint#3546 * Array: map and slice hand a @@species constructor the length ToLength produced (#3510) by @lahma in sebastienros/jint#3547 * Generators: a yield* delegation both re-delegates and keeps its place (backport of #3506 and #3518) by @lahma in sebastienros/jint#3545 * A module graph too deep to link raises an error the host can catch, instead of ending the process (#3415) by @lahma in sebastienros/jint#3548 * String to number: a trailing NUL pads neither a number string nor an array index (backport of #3544) by @lahma in sebastienros/jint#3552 * Interop: a host operator reports what it threw, and an overload the argument cannot bind to is not a match by @lahma in sebastienros/jint#3554 * Temporal: a difference past a calendar's range raises RangeError instead of spinning (#3452) by @lahma in sebastienros/jint#3555 * Interop: a read-only host collection refuses script with a JavaScript error, not the CLR's own (backport of #3385) by @lahma in sebastienros/jint#3556 * ShadowRealm: a value the host registers, and the members its wrapper builds eagerly, belong to that realm by @lahma in sebastienros/jint#3557 * Interop: two engines in one process do not decide each other's conversions and operators (backport of #3521 and #3526) by @lahma in sebastienros/jint#3559 * Interop: an index on a wrapped host collection is one property, and a filter that hides the indexer hides it by @lahma in sebastienros/jint#3562 * Interop: a host type converter's answer stays with the engine whose converter gave it by @lahma in sebastienros/jint#3563 * Interop: an operator overload is chosen by the arguments in hand (backport of #3578) by @lahma in sebastienros/jint#3611 * Intl: a calendar counting Gregorian months writes their names (backport of #3589) by @lahma in sebastienros/jint#3612 * Intl: a `-u-` extension carrying more than one key is read whole (backport of #3594) by @lahma in sebastienros/jint#3613 * JavaScriptException: only a string "stack" counts as a pre-existing stack (#3607 backport) by @lahma in sebastienros/jint#3677 * Interop: a params overload is chosen by the array's element type, and a failing element declines instead of throwing (#3764) by @lahma in sebastienros/jint#3782 * Backport #3751 to 4.x: Temporal: the persian calendar extends into proleptic years on the 33-year cycle by @lahma in sebastienros/jint#4006 * Backport #3922 to 4.x: Restore realm construction state after nesting or failure by @lahma in sebastienros/jint#4008 * Backport #3845 to 4.x: Propagate native errors during call argument evaluation by @lahma in sebastienros/jint#4009 * Backport #3877 to 4.x: Guard native recursion and forwarding paths by @lahma in sebastienros/jint#4007 **Full Changelog**: sebastienros/jint@v4.16.1...v4.16.2 Commits viewable in [compare view](sebastienros/jint@v4.16.1...v4.16.2). </details> Updated [Microsoft.AspNetCore](https://github.com/dotnet/aspnetcore) from 2.3.12 to 2.3.13. <details> <summary>Release notes</summary> _Sourced from [Microsoft.AspNetCore's releases](https://github.com/dotnet/aspnetcore/releases)._ No release notes found for this version range. Commits viewable in [compare view](https://github.com/dotnet/aspnetcore/commits). </details> Updated [Microsoft.AspNetCore.Server.Kestrel.Core](https://github.com/dotnet/aspnetcore) from 2.3.12 to 2.3.13. <details> <summary>Release notes</summary> _Sourced from [Microsoft.AspNetCore.Server.Kestrel.Core's releases](https://github.com/dotnet/aspnetcore/releases)._ No release notes found for this version range. Commits viewable in [compare view](https://github.com/dotnet/aspnetcore/commits). </details> Updated [System.Security.Cryptography.Xml](https://github.com/dotnet/dotnet) from 10.0.11 to 10.0.12. <details> <summary>Release notes</summary> _Sourced from [System.Security.Cryptography.Xml's releases](https://github.com/dotnet/dotnet/releases)._ No release notes found for this version range. Commits viewable in [compare view](https://github.com/dotnet/dotnet/commits). </details> Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) --- <details> <summary>Dependabot commands and options</summary> <br /> You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot show <dependency name> ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore <dependency name> major version` will close this group update PR and stop Dependabot creating any more for the specific dependency's major version (unless you unignore this specific dependency's major version or upgrade to it yourself) - `@dependabot ignore <dependency name> minor version` will close this group update PR and stop Dependabot creating any more for the specific dependency's minor version (unless you unignore this specific dependency's minor version or upgrade to it yourself) - `@dependabot ignore <dependency name>` will close this group update PR and stop Dependabot creating any more for the specific dependency (unless you unignore this specific dependency or upgrade to it yourself) - `@dependabot unignore <dependency name>` will remove all of the ignore conditions of the specified dependency - `@dependabot unignore <dependency name> <ignore condition>` will remove the ignore condition of the specified dependency and ignore conditions </details> Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
This was referenced Sep 14, 2026
legrab
added a commit
to legrab/pocok
that referenced
this pull request
Sep 15, 2026
Updated [Jint](https://github.com/sebastienros/jint) from 4.16.1 to 4.16.2. <details> <summary>Release notes</summary> _Sourced from [Jint's releases](https://github.com/sebastienros/jint/releases)._ ## 4.16.2 Jint 4.16.2 is a maintenance release from the `4.x` branch: **correctness and conformance fixes backported from `main`, and nothing that changes an existing API or an existing default.** If you are on 4.16.1 it is a drop-in update — every public signature is the one 4.16.0 shipped, on all five target frameworks, and the per-framework snapshots in `Jint.Tests.PublicInterface/Verify/` are unchanged. `main` remains 5.0.0 development; what is coming there is recorded as it lands in [`docs/v5-migration.md`](https://github.com/sebastienros/jint/blob/main/docs/v5-migration.md). ### Highlights **Failures that used to end the process, or never end.** A native error raised while a call's arguments are being evaluated is propagated instead of leaving an empty value behind, which on 4.16.1 could recurse until the process died — `decodeURIComponent` on a malformed sequence was enough (#4009). Native recursion and the forwarding paths through bound functions and proxies are guarded so a deep native chain raises a catchable error (#4007). A module graph too deep to link raises an error the host can catch instead of overflowing the stack (#3548). Temporal and Intl parsing cannot throw an uncatchable `RegexMatchTimeoutException` because the machine was busy (#3543), a Temporal difference past a calendar's range raises `RangeError` instead of spinning forever (#3555), and the process-wide Intl culture cache and Temporal zone cache are read-only and bounded, with a rejected zone no longer remembered — closing a script-driven unbounded growth (#3546). **Generators and built-ins, step by step.** A `yield*` delegation reached again by a loop both re-delegates and keeps its place: `countdown(3)` in a loop no longer hangs, and a delegating generator no longer returns the memoized first result (#3545). `Array.prototype.map` and `slice` hand a `@@species` constructor the length `ToLength` produced, and a non-callable `map` argument is a `TypeError` (#3547). A trailing NUL pads neither a numeric string nor an array index (#3552). A removed property slot is a tombstone rather than a free slot to reuse, so enumeration order survives a delete-and-readd (#3318), and `LengthOfArrayLike` no longer clamps through a `uint` overload (#3328). **Interop that answers for the right engine.** Two engines in one process no longer decide each other's conversions and operators (#3559), a host type converter's answer stays with the engine whose converter gave it (#3563), and a value the host registers on a `ShadowRealm` — and the members its wrapper builds eagerly — belong to that realm (#3557). Realm construction state is restored after nesting or a failure (#4008). Overload selection is by the arguments in hand: an operator overload is chosen that way (#3611), a `params` overload is chosen by the array's element type with a failing element declining rather than throwing (#3782), an overload the argument cannot bind to is not a match, and a host operator that throws reports what it threw (#3554). An index on a wrapped host collection is one property however it is spelled, and a member filter that hides the indexer hides it (#3562); a read-only host collection refuses a write with a JavaScript `TypeError` rather than the CLR's `NotSupportedException` (#3556). **Internationalization and Temporal.** The Persian calendar extends into proleptic years on its 33-year cycle, so the ends of Temporal's range land in the right Persian year (#4006); a calendar that counts Gregorian months writes their names (#3612); and a `-u-` extension carrying more than one key is read whole (#3613). **Errors.** Only a string-valued `stack` counts as a pre-existing stack when a `JavaScriptException` is built, so an accessor or non-string `stack` on a thrown object no longer breaks error reporting (#3677, reported by @jeske). Every change was verified failing-first against the unfixed branch on both .NET Framework and .NET 10, and the release was gated on a paired SunSpider and Dromaeo comparison against 4.16.1 on an idle machine: no row regressed outside run-to-run noise, most run 1–4 % faster. ## What's Changed * Backport: a removed property slot is a tombstone, not a free slot to reuse (#3273) by @lahma in sebastienros/jint#3318 * Backport: LengthOfArrayLike, delete the uint overload rather than clamp it (#3248) by @lahma in sebastienros/jint#3328 * Temporal and Intl parsing cannot fail because the machine was busy (#3486) by @lahma in sebastienros/jint#3543 * Backport: the process-wide Intl culture cache and Temporal zone cache are read-only and bounded, and a rejected zone is not remembered by @lahma in sebastienros/jint#3546 * Array: map and slice hand a @@species constructor the length ToLength produced (#3510) by @lahma in sebastienros/jint#3547 * Generators: a yield* delegation both re-delegates and keeps its place (backport of #3506 and #3518) by @lahma in sebastienros/jint#3545 * A module graph too deep to link raises an error the host can catch, instead of ending the process (#3415) by @lahma in sebastienros/jint#3548 * String to number: a trailing NUL pads neither a number string nor an array index (backport of #3544) by @lahma in sebastienros/jint#3552 * Interop: a host operator reports what it threw, and an overload the argument cannot bind to is not a match by @lahma in sebastienros/jint#3554 * Temporal: a difference past a calendar's range raises RangeError instead of spinning (#3452) by @lahma in sebastienros/jint#3555 * Interop: a read-only host collection refuses script with a JavaScript error, not the CLR's own (backport of #3385) by @lahma in sebastienros/jint#3556 * ShadowRealm: a value the host registers, and the members its wrapper builds eagerly, belong to that realm by @lahma in sebastienros/jint#3557 * Interop: two engines in one process do not decide each other's conversions and operators (backport of #3521 and #3526) by @lahma in sebastienros/jint#3559 * Interop: an index on a wrapped host collection is one property, and a filter that hides the indexer hides it by @lahma in sebastienros/jint#3562 * Interop: a host type converter's answer stays with the engine whose converter gave it by @lahma in sebastienros/jint#3563 * Interop: an operator overload is chosen by the arguments in hand (backport of #3578) by @lahma in sebastienros/jint#3611 * Intl: a calendar counting Gregorian months writes their names (backport of #3589) by @lahma in sebastienros/jint#3612 * Intl: a `-u-` extension carrying more than one key is read whole (backport of #3594) by @lahma in sebastienros/jint#3613 * JavaScriptException: only a string "stack" counts as a pre-existing stack (#3607 backport) by @lahma in sebastienros/jint#3677 * Interop: a params overload is chosen by the array's element type, and a failing element declines instead of throwing (#3764) by @lahma in sebastienros/jint#3782 * Backport #3751 to 4.x: Temporal: the persian calendar extends into proleptic years on the 33-year cycle by @lahma in sebastienros/jint#4006 * Backport #3922 to 4.x: Restore realm construction state after nesting or failure by @lahma in sebastienros/jint#4008 * Backport #3845 to 4.x: Propagate native errors during call argument evaluation by @lahma in sebastienros/jint#4009 * Backport #3877 to 4.x: Guard native recursion and forwarding paths by @lahma in sebastienros/jint#4007 **Full Changelog**: sebastienros/jint@v4.16.1...v4.16.2 Commits viewable in [compare view](sebastienros/jint@v4.16.1...v4.16.2). </details> [](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) --- <details> <summary>Dependabot commands and options</summary> <br /> You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot show <dependency name> ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself) </details>
This was referenced Sep 16, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Backports #3764 (
main) to the 4.x maintenance branch. Both defects were confirmed present on 4.x by running the ported tests against unfixed code first.The two defects
A. A JavaScript array short-circuited overload scoring above the converter probe. A
paramscall bundles its trailing arguments into oneJsArraybefore overload resolution runs, soInteropHelper.CalculateMethodParameterScorerated three candidates differing only in their element type —CDecimal[],CInteger[],CLong[]— with one rule, "is an array, wants an array", that answered a flat2for every one of them. The element type was never consulted, the converter probe below that rule (the #3407 fix, which 4.x already has) was never reached, and declaration order decided. Where the first-declared candidate happened to be convertible it answered silently and wrongly; where it was not, the conversion'sInvalidCastExceptionleft through the embedder'sEvaluate— invisible to a scriptcatchand to a hostcatch (JavaScriptException)alike.B. The composite branches of
DefaultTypeConverter.TryConvertconverted their parts through the public, throwingConvert. AList<T>orCollection<T>item, aT[]element, a target dictionary's value and a member of a POCO built from a dictionary all ignored thepropagateExceptionflag their own frame had been called with, so a method documented as returningfalsethrew. That is not something the candidate loop inMethodInfoFunction.Callcan move on from: it tries candidates in score order and declines its way to the next, and an exception ends the call rather than the candidate.They are fixed together, because fixing A by asking the converter per element throws until B is fixed.
TryConvertPartroutes all five composite sites through the flag their frame was given. It mirrorsConvert— the virtualTryConvertfirst, so a subclass override still answers for the parts — so behaviour underpropagateException: trueis unchanged.CalculateParameterTypeScoreis the type-level core of the parameter score, so an element with noParameterInfoof its own can be scored by the same rules. An array parameter now scores its base2plus its worst element, up to eight of them, and returns-1on the first element that cannot bind at all. Element types anyJsValueis assignable to —object,JsValue— are carved out and keep the flat base, orparams object[]andparams JsValue[]would rank below the scalar overload beside them.Deliberately out of scope, exactly as on
main:MethodDescriptor.Call'sTypeReferenceconstructor lane keeps its throwingConvertand gets no retry loop (correct selection is what repairs it), and an empty JS array against severalparams T[]overloads stays ambiguous and keeps today's answer.Failing first
Both files were ported and run against unfixed 4.x before
Jint/was touched. Identical counts on both legs (net472, which exercises Jint'snet462-compiled asset, andnet10.0):Jint.Tests.PublicInterface/HostArrayElementOverloadTestsJint.Tests/Runtime/CompositeConversionDeclineTestsThe three that passed unfixed in the first file are exactly the ones meant to: the empty-array pin (
AnEmptyArrayKeepsTodaysAnswer, deliberately unchanged behaviour) and the two carve-out guards (params object[],params JsValue[]). The six that passed unfixed in the second are the fiveConvert-still-throws cases and the convertible-composite control — the half that pins what must not change.The two representative unfixed failures:
math.Add(a, b)with twoCIntegers →System.InvalidCastException: Invalid cast from '…' to '…+CDecimal'out ofEvaluate, throughMethodInfoFunction.TryCall→DefaultTypeConverter.TryConvert→Convert.converter.TryConvert(new object[] { new Widget() }, typeof(Gadget[]), …)threw instead of returningfalse.Divergences from
mainactually foundparameterValue.IsSpecArray()onmainisparameterValue.IsArray()on 4.x — confirmed.JsProxyoverrides it on 4.x too, so the Proxy carve-out (is not ArrayInstancekeeps the base score, no traps run during scoring) still holds and the comment was reworded from "spec array" to "array".engine._typeConverteronmainisengine.TypeConverteron 4.x — confirmed, but it did not affect this change: the only site reading it is the existing Interop: a plain type mismatch scores 100 instead of being discarded, so 'text' + an overloaded CLR value throws #3407 probe, which the port leaves untouched.ClrTypeConverteronmainisITypeConverteron 4.x — confirmed as the base type ofDefaultTypeConverter. It did not affectTryConvertPart, whose doc comment references onlyConvert,TryConvertandOptions.InteropOptions.ExceptionHandler, all of which exist on 4.x with the same names.foreach (var member in type.GetMembers())loop with aMemberType != Property && != Fieldfilter, notmain's extractedstatic void CopyDictionaryEntryToMember(…)local function over separateGetProperties()/GetFields()passes.main's refactor was not imported;TryConvertPartis called inline and the loopreturn falses on a decline.catchin theConvert.ChangeTypefallback has noThrow.MustPropagateHostException(e)call — confirmed, and left alone.ArrayInstance.GetLength()(internal override uint) andTryGetValue(uint, out JsValue)(public bool) exist on 4.x with the same signatures — no adaptation needed.Two more that turned up during the port:
Could not resolve a constructor for type {type} for given arguments;mainreworded it toCould not resolve a constructor for the specified arguments..AConstructorArgumentNoOverloadAcceptsIsACatchableResolutionFailureasserts 4.x's wording (with a*wildcard for the type name). The behaviour being pinned — a catchableJavaScriptException/ script-visibleTypeErrorinstead of a rawInvalidCastException— is identical, and that test is red on unfixed 4.x either way.[Test]→[Fact]throughout (no[TestCase]in either file).Invoking(…)and the AwesomeAssertions global usings are already present on 4.x in both projects, so the assertion style is unchanged.maincreatedJint.Tests/Runtime/Interop/forCompositeConversionDeclineTests.cs; 4.x has no such folder and keepsDefaultTypeConverterTests.csdirectly inJint.Tests/Runtime/, so the ported file sits there with namespaceJint.Tests.Runtime.No
AGENTS.mdchange. 4.x has noJint/Runtime/Interop/AGENTS.md— the co-located split ismain-only, and 4.x's single rootAGENTS.mdcarries no "Overload scoring's last rule" bullet (and no mention of #3407) to extend. Nodocs/v5-migration.mdrow either; that file ismain-only.Verification
All in Release, no
--no-build,TreatWarningsAsErrorson, both TFMs where the project multi-targets:Jint.TestsJint.Tests.PublicInterfaceJint.Tests.CommonScriptsJint.Tests.Test262test262 matches the branch control exactly, with neither of the two known load flakes (
intl402/supportedLocalesOf-unicode-extensions-ignored.js,staging/sm/Array/toSpliced-dense.js) firing this run. Full solution build: 0 errors, and the only warning is the pre-existingMSB3277reference conflict inJint.Tests.CommonScriptsonnet472, untouched by this change.🤖 Generated with Claude Code
https://claude.ai/code/session_01LfyCDDqtkhyWVEFHKWhZfu