Skip to content

Intl: a -u- extension carrying more than one key is read whole (backport of #3594) - #3613

Merged
lahma merged 1 commit into
sebastienros:4.xfrom
lahma:backport/3594-unicode-extension-scanner
Sep 2, 2026
Merged

lahma merged 1 commit into
sebastienros:4.xfrom
lahma:backport/3594-unicode-extension-scanner

Conversation

@lahma

@lahma lahma commented Sep 2, 2026

Copy link
Copy Markdown
Collaborator

Backport of #3594 (main squash 53ef37e79), which closed #3573.

The defect, live on 4.x

new Intl.DateTimeFormat('en-US-u-ca-buddhist-nu-arab') resolves to a bare en-US with gregory and latn, losing both keys. Either key on its own is read; the two together lose both, and the resolved locale loses the extension with them. Intl.NumberFormat has it too, while Intl.Locale and Intl.getCanonicalLocales read the same tag correctly.

Each constructor carried its own scanner, and each ended a key's value by consuming the next key into it — ca read back as "buddhist-nu", which resolves to no calendar, so the option was dropped and the extension never made it into the resolved locale. Eight such scanners existed under Jint/Native/Intl.

Measured on this branch, before and after. DTF is new Intl.DateTimeFormat(tag, { hour: 'numeric' }).resolvedOptions(), NF is new Intl.NumberFormat(tag).resolvedOptions():

requested tag before after
en-US-u-ca-buddhist-nu-arab DTF en-US / gregory / latn DTF en-US-u-ca-buddhist-nu-arab / buddhist / arab
en-US-u-nu-arab-ca-buddhist DTF en-US / gregory / latn DTF en-US-u-ca-buddhist-nu-arab / buddhist / arab
en-US-u-ca-buddhist-hc-h23 DTF en-US / gregory / latn / h12 DTF en-US-u-ca-buddhist-hc-h23 / buddhist / latn / h23
en-US-u-hc-h23-nu-arab-ca-buddhist DTF en-US-u-nu-arab / gregory / arab / h12 DTF en-US-u-ca-buddhist-hc-h23-nu-arab / buddhist / arab / h23
en-US-u-ca-islamic-civil-nu-arab DTF en-US / gregory / latn DTF en-US-u-ca-islamic-civil-nu-arab / islamic-civil / arab
en-US-u-foo-ca-buddhist-nu-arab DTF en-US / gregory / latn DTF en-US-u-ca-buddhist-nu-arab / buddhist / arab
en-US-u-nu-arab-x-private DTF en-US / latn DTF en-US-u-nu-arab / arab
en-US-u-ca-buddhist-nu-arab NF en-US / latn NF en-US-u-nu-arab / arab
en-US-u-nu-arab-ca-buddhist NF en-US / latn NF en-US-u-nu-arab / arab

Every "after" value is what ICU — and therefore V8 (Node 24, full ICU) — answers for the same tag.

This changes what scripts see

Stated plainly, as #3556 did for read-only host collections. A script reading resolvedOptions() for a tag that carries more than one -u- key gets different values than it did: the keys it asked for, and a locale that carries them. A tag with one key, or none, resolves exactly as before — those lanes are pinned in the new tests precisely so the change stays confined to the case that was broken. Anything downstream that formats through such a formatter (dates in a Buddhist calendar, numbers in Arabic-Indic digits) formats differently as a result, which is the point of the fix.

ResolveLocale step 13's precedence is untouched, and now pinned: an option still supersedes the tag's keyword and still removes that keyword from the resolved locale — for one key, and for one key beside another.

The fix

The eight scanners are replaced by one. UnicodeExtension owns the rule https://unicode.org/reports/tr35/#unicode_locale_extensions states — a key is two characters, a value is the 3-to-8-character subtags after it, and both end at the next key or the next singleton — and answers for reading a keyword, enumerating them, removing the sequence, and rewriting one key. Intl.Locale's own whole-tag parser and CanonicalizeUnicodeLocaleId take their key test from it as well, so nothing in the engine can drift about where one keyword ends and the next begins.

Divergence from the main PR

This is not a blind pick; four files needed a merge, and all four for the same reason: main's Intl has moved on around this code (the provider chain that is out of scope for 4.x), so git apply -3 pulled in signature changes that belong to other PRs.

file what main's patch wanted what landed here
DurationFormatConstructor private string ResolveNumberingSystem(…, string locale) reading IntlUtilities.IsSupportedNumberingSystem / GetLocaleDefaultNumberingSystem 4.x's private static string ResolveNumberingSystem(string?, string?) kept as-is; only ParseNumberingSystemExtension is deleted and its call site replaced with UnicodeExtension.GetKeywordValue. Main's spec-citation doc comment is kept — it describes step 13 either way.
NumberFormatConstructor, RelativeTimeFormatConstructor private bool IsSupportedNumberingSystem(…) kept private static bool; only ExtractNumberingSystemFromLocale is deleted
DateTimeFormatConstructor delete a region main no longer has CanonicalizeCalendar in CanonicalizeCalendar kept, ExtractUnicodeExtensionFromLocale deleted
Polyfills.cs insert the string.Concat(ROS<char>, ROS<char>) block where 4.x has its #if NETFRAMEWORK span-Contains block inserted ahead of it, both intact

docs/v5-migration.md dropped — it does not exist here. Jint/Native/Intl/UnicodeExtension.cs, CollatorConstructor, DefaultCldrProvider, IntlUtilities and LocaleConstructor applied cleanly and are byte-identical to main's.

TFM check (asked for explicitly, since 4.x is net462;netstandard2.0;netstandard2.1;net8.0;net10.0):

  • The string.Concat span polyfill's guard is #if !NET8_0_OR_GREATER, which covers net462, netstandard2.0 and netstandard2.1 here exactly as it covers net472, netstandard2.0 and netstandard2.1 on main — same three downlevel assets, same reason. 4.x's Polyfills already uses the C# 14 extension(string) member syntax the block needs (string.Join(char, …) right above it). No existing Concat polyfill to collide with.
  • UnicodeExtension.IsKey is shared by IntlUtilities.CanonicalizeUnicodeLocaleId and LocaleConstructor and uses nothing newer than ReadOnlySpan<char>.
  • All five assets build with 0 errors and 0 warnings.

Evidence

Jint.Tests/Runtime/IntlUnicodeExtensionTests.cs (42 cases) run against unfixed 4.x first. To make the file compile before the fix, UnicodeExtension.cs and the polyfill were added on their own — nothing calls the class at that point, so engine behaviour is unchanged and the reader's own unit tests act as a control:

leg before after
net472 Failed: 11, Passed: 31, Total: 42 Failed: 0, Passed: 42
net10.0 Failed: 11, Passed: 31, Total: 42 Failed: 0, Passed: 42

The 31 that passed before are the 23 GetKeywordValue / RemoveSequence / WithKeyword cases (the new reader is right before any consumer uses it), plus Intl.Collator's three keys and RelativeTimeFormat / DurationFormat's nu — those two scanners split the sequence on - and looked for a key by name, so they already survived a second key. The 11 failures are Intl.DateTimeFormat (7) and Intl.NumberFormat (2) losing keys, plus the multi-subtag/attribute case and the option-precedence case.

All 280 Jint.Tests Intl cases pass on both legs. Full dotnet build -c Release: 0 errors, 0 warnings. Full dotnet test -c Release:

  • Jint.Tests 7041/7041 (net10.0), 6956/6956 (net472)
  • Jint.Tests.PublicInterface 1820/1820 (net10.0), 1812/1812 (net472)
  • Jint.Tests.CommonScripts 28/28 both legs, Jint.Tests.SourceGenerators 52/52
  • Jint.Tests.Test262 102,499 passed / 0 failed / 185 skipped of 102,684 — exactly the 4.x control, with not even the usual supportedLocalesOf load flake this run. The pass count is unchanged, so no exclusion becomes removable: every test the corpus runs through these constructors was already passing with a single-key tag, and the multi-key tags the defect lost are ones test262 does not exercise here.

Backport of sebastienros#3594.

`new Intl.DateTimeFormat('en-US-u-ca-buddhist-nu-arab')` resolved to a bare `en-US`
with `gregory` and `latn`, losing both keys. Either key on its own was read; the two
together lost both, and the resolved locale lost the extension with them.
`Intl.NumberFormat` had it too, while `Intl.Locale` and `Intl.getCanonicalLocales`
read the same tag correctly.

Each constructor carried its own scanner, and each ended a key's value by consuming
the next key into it - `ca` read back as "buddhist-nu", which resolves to no calendar,
so the option was dropped and the extension never made it into the resolved locale.
Eight such scanners existed under `Jint/Native/Intl`.

They are replaced by one. `UnicodeExtension` owns the rule
https://unicode.org/reports/tr35/#unicode_locale_extensions states - a key is two
characters, a value is the 3-to-8-character subtags after it, and both end at the next
key or the next singleton - and answers for reading a keyword, enumerating them,
removing the sequence, and rewriting one key. `Intl.Locale`'s own whole-tag parser and
`CanonicalizeUnicodeLocaleId` now take their key test from it as well, so nothing in
the engine can drift about where one keyword ends and the next begins.

The precedence `ResolveLocale` step 13 sets is untouched, and pinned: an option still
supersedes the tag's keyword and still removes it from the resolved locale, for one key
and for one key beside another.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014W5mbjGhyvgAS4pivXoc4S
@lahma
lahma merged commit 268706c into sebastienros:4.x Sep 2, 2026
9 of 10 checks passed
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>
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>

[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=Jint&package-manager=nuget&previous-version=4.16.1&new-version=4.16.2)](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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant