Skip to content

10.x: the default IFormattable.ToString of IValueSetFactory still compiles to a trap under Native AOT with the .NET 11 SDK; only the per-family overrides from #299 keep it out (dotnet/runtime#136073) #315

Closed

Description

@CaffeinatedCoder

Correction (2026-10-19)

The first version of this issue said a consumer-defined set type would still trap under Native AOT
because it inherits the default. That is wrong. IValueSetFactory<TSet, T> declares
internal abstract static TSet FromTrusted(...), so no assembly outside this repository (and its
InternalsVisibleTo friends) can implement it: a scratch project doing so fails with CS0535 on
FromTrusted. The remarks' "Implement this interface on a concrete set type" are addressed to this
library. There is no consumer-facing gap, and the severity is not that of a bug.

What is left

#299 keeps the trap out by giving each of our 17 families its own IFormattable.ToString, so the
default in IValueSetFactory<TSet, T> is never the implementation a compiled consumer runs. That
holds only as long as every set type, present and future (core, the NodaTime satellite, anything
else with InternalsVisibleTo), carries the override. A new family that forgets it compiles, passes
every test on the .NET 10 SDK that CI runs, and traps (exit 133, no output) only in a net11.0
Native AOT publish, which only a manual SMOKE_AOT_SDK run exercises (#297 does not give the 10.x
CI that leg).

Root cause, from hez2010 on dotnet/runtime#136073 (2026-10-19): ILCompiler inlines a small default
interface method into the instantiating thunk of a shared-generic interface, where the receiver is
typed as the thunk's module type, so the cast of this in (IValueSet<T>)this fails. Their
workaround is [MethodImpl(MethodImplOptions.NoInlining)] on the default. The upstream issue is
still open and untriaged.

IRangeFactory<TRange, T> has a default IFormattable.ToString of the same kind. It did not trap on
RC2 (the AOT leg prints range ToString cases to the end); the likely reason is that its body is too
large to inline, which has not been measured.

Candidate change

  • [MethodImpl(MethodImplOptions.NoInlining)] on the default in IValueSetFactory<TSet, T>, keeping
    the per-type overrides, so a family that lacks one is slow rather than fatal.
  • A reflection test in the conventions project that the default carries the flag.
  • Measured first, see below: the 10.0.0 state traps in the AOT consumer of
    test/consumer-smoke-test.sh and runs with the attribute.

Whether this is worth shipping in 10.1.0 is open: it is defense in depth, not a fix.

Measured (2026-10-19)

.NET SDK 11.0.100-rc.2.26504.105, osx-arm64, SMOKE_AOT_SDK=11.0.100-rc.2.26504.105 test/consumer-smoke-test.sh
from release/10.x (b9d7fa2):

Sets Default Native binary
10.0.0 state (the overrides of e54ed35 reverted) no attribute exit 133 after aot-float64set, as #291 saw
10.0.0 state [MethodImpl(NoInlining)] ran to the end; "ToString on every value set family" passes
overrides in place, GuidSet alone reverted no attribute ran to the end (a single family does not trap)

hez2010's workaround holds on RC2. The range default (IRangeFactory) printed every range in the same
publishes, with and without the attribute on the set default, so it is left alone.

The change is PR-ready as one chore: commit: the attribute, a comment saying why, and a conventions
test asserting the flag by reflection (the smoke run cannot be in CI, #297). No public surface or
answer changes, so no changelog line.

The measurement is posted upstream: dotnet/runtime#136073 (comment). The change is PR #316.

Activity

  1. added this to the 10.1.0 milestone on Oct 19, 2026
  2. added
    bugSomething isn't working
    area/value-setsValue set families and wrapper arities
    area/aotNative AOT and trimming
    package/coreAffects CodoMetis.ValueRanges
    severity/mediumInconsistency or failure in a narrow scenario
    on Oct 19, 2026
  3. removed
    bugSomething isn't working
    severity/mediumInconsistency or failure in a narrow scenario
    on Oct 19, 2026
  4. changed the title [-]10.x: a consumer-defined value set still traps under Native AOT with the .NET 11 SDK, because #299 only overrides our own families (dotnet/runtime#136073)[/-] [+]10.x: the default IFormattable.ToString of IValueSetFactory still compiles to a trap under Native AOT with the .NET 11 SDK; only the per-family overrides from #299 keep it out (dotnet/runtime#136073)[/+] on Oct 19, 2026
  5. added
    choreBuild, CI, packaging, refactoring with no behaviour change
    on Oct 19, 2026
  6. CaffeinatedCoder commented on Oct 19, 2026

    @CaffeinatedCoder
    OwnerAuthor

    Fixed on release/10.x by PR #316, merge commit 3ed738e (a closing keyword acts only on main). The port to main follows as its own PR.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    area/aotNative AOT and trimmingarea/value-setsValue set families and wrapper aritieschoreBuild, CI, packaging, refactoring with no behaviour changepackage/coreAffects CodoMetis.ValueRanges

    Projects

    No projects

      Milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions