Skip to content

AOT M1-G: one matching rule for every built-in type name - #8613

Merged
Aaronontheweb merged 1 commit into
aot/m1-f-canary-ci-and-targetsfrom
aot/m1-g-one-builtin-name-rule
Sep 25, 2026
Merged

Aaronontheweb merged 1 commit into
aot/m1-f-canary-ci-and-targetsfrom
aot/m1-g-one-builtin-name-rule

Conversation

@Aaronontheweb

@Aaronontheweb Aaronontheweb commented Sep 23, 2026 •

Copy link
Copy Markdown
Member

Part of the AOT milestone-1 stack (stack #8607). Sits on top of #8608.

Problem

The stack had two rules for matching a HOCON type name against Akka's built-in types:

  • Dictionary tables (loggers, scheduler, mailboxes, message-queue semantics, routers, supervisor-strategy configurators, serializers and serialization bindings) required exactly Ns.T or Ns.T, Akka, after StripAssemblyIdentity.
  • BufferPools.MatchesBuiltIn, DnsExt and the serialization-identifiers matcher split at the comma and compared the assembly name case-insensitively, so they also accepted Ns.T,Akka and Ns.T, akka, as Type.GetType did.

With Akka.DynamicTypeLoading on nobody could tell, because a table miss falls back to Type.GetType. With it off, "Akka.Dispatch.BoundedMailbox,Akka" threw at a mailbox site but was accepted as a buffer-pool class.

Change

  • Two internal helpers in Akka.Util.TypeExtensions:
    • TrySplitTypeName strips the assembly identity, then splits at the first comma outside a generic argument list. The split used to be private to SerializerIdentifierHelper.
    • ToBuiltInAkkaTypeName returns the bare type name when the assembly is absent or is Akka (case-insensitive), and null for any other assembly.
  • Every table has one key per type (the bare name), and every lookup goes through ToBuiltInAkkaTypeName. Serialization bindings accept the four framework assembly names instead.
  • BufferPools.MatchesBuiltIn is deleted. BufferPools.Create, DnsExt and SerializerIdentifierHelper use the shared helpers.
  • The eight copies of the "two spellings are deliberate" comment are gone.
  • Net: about 35 fewer lines of product code in src/core/Akka.

With the switch on, nothing changes. With it off, every site accepts the spellings Type.GetType accepted for Akka's own types. Ledger: new G row, and the A row no longer claims two keys per table.

A bare name (no comma) is not trimmed. HOCON keys arrive untrimmed, and trimming would let a padded akka.actor.mailbox.requirements key collide with core's own entry. An existing spec guards this.

Tests

Verification (local)

  • Core builds with -warnaserror at 0/0. The solution builds.
  • Akka.Tests: 1425 passed, 0 failed.
  • Akka.API.Tests passes unchanged. No public API change.
  • AOT canary: unrooted publish runs and prints [canary] OK. Rooted publish shows no new warnings against the 12-entry baseline.

@Aaronontheweb
Aaronontheweb added this pull request to stack #8607 September 23, 2026 15:28
@Aaronontheweb Aaronontheweb added the AOT Ahead-of-Time (AOT) Compilation label Sep 23, 2026
@Aaronontheweb Aaronontheweb added this to the 1.6.0 milestone Sep 23, 2026
@Aaronontheweb Aaronontheweb changed the title Collapse every BuiltIn* type-name table to one key, widen matching to Type.GetType's rules AOT M1-G: one matching rule for every built-in type name Sep 23, 2026
@Aaronontheweb
Aaronontheweb force-pushed the aot/m1-g-one-builtin-name-rule branch from 817c0a1 to 3edc044 Compare September 23, 2026 18:09
@Aaronontheweb
Aaronontheweb force-pushed the aot/m1-g-one-builtin-name-rule branch 3 times, most recently from d69ea0f to bf6cae6 Compare September 24, 2026 03:31
@Aaronontheweb
Aaronontheweb force-pushed the aot/m1-g-one-builtin-name-rule branch 2 times, most recently from 4548467 to 5440d55 Compare September 24, 2026 15:26
@Aaronontheweb
Aaronontheweb removed this pull request from stack #8607 September 24, 2026 16:42
@Aaronontheweb
Aaronontheweb added this pull request to stack #8632 September 24, 2026 16:43
@Aaronontheweb
Aaronontheweb force-pushed the aot/m1-g-one-builtin-name-rule branch from 5440d55 to 91f1ce1 Compare September 24, 2026 16:44
@Aaronontheweb
Aaronontheweb force-pushed the aot/m1-g-one-builtin-name-rule branch from 91f1ce1 to 39bd1e4 Compare September 24, 2026 17:00
… Type.GetType's rules

Every BuiltIn* table (loggers, schedulers, mailboxes, message-queue semantics,
routers, supervisor-strategy configurators, serializers, serialization
bindings, the DNS provider) carried two keys per type -- the bare name and
"Ns.T, Akka" -- and matched only those two spellings after stripping the
assembly identity. Type.GetType accepts more: any assembly identity, an
optional space after the comma, and a case-insensitive assembly name.

Add TypeExtensions.TrySplitTypeName and TypeExtensions.ToBuiltInAkkaTypeName
and route every table lookup through the latter, so each table now carries a
single bare-name key and accepts the same spellings Type.GetType did.
SerializerIdentifierHelper keeps its own two-pass, any-assembly matching but
now shares TrySplitTypeName instead of its private comma-splitting code.

Record the widened matching as a v1.6 breaking change and note where the A
row's two-key description no longer applies.
@Aaronontheweb
Aaronontheweb force-pushed the aot/m1-g-one-builtin-name-rule branch from 39bd1e4 to 9f06d36 Compare September 25, 2026 00:46

@Aaronontheweb Aaronontheweb left a comment

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Internal type matchers only need one record now - don't need the extra assembly name qualification. Matches what our reflection-based system did before.

LGTM

@Aaronontheweb
Aaronontheweb merged commit a498171 into dev Sep 25, 2026
17 checks passed
@Aaronontheweb
Aaronontheweb deleted the aot/m1-g-one-builtin-name-rule branch September 25, 2026 02:11
Aaronontheweb added a commit that referenced this pull request Sep 29, 2026
…esolves without reflection (#8654)

* AOT: resolve Akka.Hosting's LoggerFactoryLogger in akka.loggers without reflection

With Akka.DynamicTypeLoading off, LoggingBus only accepted the three loggers
in Akka.dll, so any Akka.Hosting app using AddLoggerFactory() failed at
startup with a NotBuiltIn ConfigurationException.

LoggingBus now checks a first-party table after the built-in one. A row
matches only on the exact type name plus assembly (identity stripped, per
#8613), then loads its own literal through a DynamicallyAccessedMembers
string parameter so the trimmer keeps the type. An assembly that will not
load counts as absent and falls through to today's behavior. Configs that
name only core loggers never probe.

Tests: switch-off startup and switch-on parity in Akka.Hosting.Tests;
no-probe and absent-assembly checks in Akka.Tests.

* Review fixes: simplify GetFirstPartyLoggerType, fix a no-probe test that couldn't fail, add switch-on version-skew coverage

- Drop the LoadFirstPartyLoggerType try/catch helper: Type.GetType on a literal
  is a trimmer intrinsic, so the switch arm calls it directly (matches
  GetBuiltInLoggerType's style). throwOnError defaults to false, so a missing
  Akka.Hosting still returns null; a broken dll now surfaces its own exception
  instead of being swallowed.
- BuiltInLoggersSpec's "never probes" test only named built-in loggers, so
  GetFirstPartyLoggerType never ran. It now uses CustomLoggerConfig, which is
  not built in, so the lookup actually executes and asserts Akka.Hosting is
  never probed.
- Add a switch-on version-skew test to FirstPartyLoggerSpec: a Hosting logger
  name pinned to a different Akka.Hosting version now resolves with the
  DynamicTypeLoading switch on, not just off. Make the spec sealed and take
  ITestOutputHelper.
- Amend the #8603 ledger row: switch-off apps can also use Akka.Hosting's
  LoggerFactoryLogger, not just the three core loggers. Add a new row for
  this PR.
Aaronontheweb added a commit to Aaronontheweb/akka.net that referenced this pull request Sep 30, 2026
…t-party extensions as not-built-in

Two review fixes on top of the extensions/provider switch-off guard:

1. ProviderSelection.GetProvider matched akka.actor.provider by exact string, so
   a spelling variant of a built-in provider - no space after the comma (e.g.
   "Akka.Cluster.ClusterActorRefProvider,Akka.Cluster"), or a versioned
   assembly-qualified name - fell through to Custom. With the switch off that
   meant a working built-in provider threw NotBuiltIn. GetProvider now
   normalizes through TypeExtensions.TrySplitTypeName (the akkadotnet#8613 rule: strip
   the assembly identity, split at the comma, compare the assembly
   case-insensitively) against a small BuiltInProviders table, so every
   accepted spelling maps to the same ProviderSelection instead. This also
   fixes Settings.HasCluster being wrongly false for such a spelling,
   independent of the switch.

2. LoadExtensions treated a first-party extensions-table name whose assembly
   isn't deployed (TryCreateFirstPartyExtension returns null either way) the
   same as a name that isn't in the table at all, so with the switch off it
   threw NotBuiltIn for a name akkadotnet#8648 already promised to log-and-skip. A new
   IsFirstPartyExtensionName reports a table hit regardless of whether the
   assembly loads, so LoadExtensions can log-and-skip the absent-module case
   before reaching the switch-off guard - matching the switch-on behavior,
   which already fell through to the same log message.

Tests added to AkkaFeaturesSpec (provider spelling classification and its
end-to-end consequence in both switch states, plus the absent-assembly
extension case) and ExtensionsSetupSpec (IsFirstPartyExtensionName). Updates
the BREAKING_CHANGES_V1.6.md row to name both cases.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

AOT Ahead-of-Time (AOT) Compilation

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant