Skip to content

Compile time: share settings registration code across settings - #15454

Merged
vorporeal merged 2 commits into
masterfrom
david/compile-time-settings-macros
Aug 23, 2026
Merged

Compile time: share settings registration code across settings#15454
vorporeal merged 2 commits into
masterfrom
david/compile-time-settings-macros

Conversation

@vorporeal

Copy link
Copy Markdown
Contributor

Description

This is PR 2 of 3 in a stack that reduces the compile time of the warp crate. It is stacked on #15453.

The settings macros are the largest single source of macro-expanded code in the warp crate. Before this change, they produced 10.7 MB of the 36.7 MB total macro expansion, and the settings registration path produced about 660K lines of LLVM IR.

This PR makes two changes:

  1. Move the registration body out of the macro. The register_settings_events! macro expanded a full registration function (parse, update, clear, load, equality, and syncable callbacks) for every one of the ~300 registered settings. The body now lives in settings::registration::register_setting_events_impl, which is generic over only the settings group type and the value type. Settings that share those two types (for example, the many bool settings in one group) now share one compiled instantiation. A thin per-setting wrapper gathers the Setting trait metadata (storage key, defaults, platforms, and so on) into a plain struct before it hands off to the shared body.
  2. Emit change events through a trait. define_setting! and implement_setting_for_enum! expanded four separate concat_idents! blocks per setting to construct the group's *ChangedEvent variant at each emit site. Each setting now gets one small SettingChangeEvent impl, and the emit sites call <Self as SettingChangeEvent>::change_event(reason). This cuts concat_idents! from 606 uses (2.49 MB) to 351 uses (0.13 MB).

How method resolution is preserved

The old macro expansion called setting methods (for example set_value and current_value_is_syncable) at the expansion site. This matters: Theme, SystemThemes, and one test type define inherent current_value_is_syncable methods that shadow the Setting trait default. To keep this behavior, the macro builds a SettingCallbacks struct of function pointers at its expansion site. Each callback is a small non-capturing closure with the concrete setting type, so inherent methods still shadow trait defaults exactly as before. The shared generic body only invokes the function pointers.

Alternatives considered and discarded

  • Per-setting generic function (measured). A first version kept the whole body generic over the setting type S. It removed the macro bytes but only cut 22K IR lines (−0.13%), because the body still monomorphized once per setting. The (group, value) split in this PR cuts the registration path from 660K to 238K IR lines.
  • Trait default method on Setting. Moving the body into a default method has the same per-setting monomorphization problem, and it changes method resolution for the shadowed inherent methods.
  • Full type erasure with Box<dyn Any>. This would compile the body exactly once, but it needs runtime downcasts on every settings update and loses type safety. The (group, value) fn-pointer design gets most of the win with no runtime cost.
  • Group-level registration aggregation. Registering a whole group in one call could remove more per-setting glue, but it is a larger behavioral change and risks the schema byte-identity guarantee. It can be a follow-up.

Measured results (Apple M5 Pro, rustc 1.92.0, dev profile, relative to PR 1)

  • cargo llvm-lines -p warp --lib: 17,279,212 → 17,022,929 lines (−1.5%); copies 580,747 → 573,201. The settings registration path drops from ~660K to ~238K lines (−64%).
  • Macro expansion (-Zmacro-stats): 36.7 MB → 32.2 MB (−12.4% versus master). The 1.99 MB generate_settings_event_fn! output is gone.
  • Touch-incremental rebuild of the warp lib: unchanged (15.4/14.8 s versus 15.4/14.6 s).
  • Clean rebuild of the warp lib (deps cached): unchanged within run-to-run noise (71–74 s versus 68 s; master measured ~71 s on the same machine).

The wall-clock effect of this PR alone is within measurement noise. The change still removes a large fixed cost from macro expansion and codegen, and it makes each new setting much cheaper to add.

Linked Issue

N/A — compile-time work from a profiling session.

  • The linked issue is labeled ready-to-spec or ready-to-implement.
  • Where appropriate, screenshots or a short video of the implementation are included below (especially for user-visible or UI changes).

Testing

  • cargo nextest run -p settings: 71/71 passed.
  • cargo nextest run -p warp -E 'test(cloud_preferences) or test(theme) or test(/settings::/)': 168/168 passed.
  • generate_settings_schema output (221 settings) is byte-identical to the output on the base branch.
  • ./script/format and all presubmit clippy passes are clean.

This is a pure refactor with no user-visible behavior change, so no new tests were added. The schema byte-identity check plus the existing settings test suite cover the behavior that could regress.

  • I have manually tested my changes locally with ./script/run

Agent Mode

  • Warp Agent Mode - This PR was created via Warp's AI Agent Mode

Warp conversation

Co-Authored-By: Warp agent@warp.dev

CHANGELOG-NONE

@warp-for-oss

warp-for-oss Bot commented Aug 22, 2026

Copy link
Copy Markdown
Contributor

@vorporeal

I'm starting a first review of this pull request.

You can view the conversation on Warp.

I completed the review and no human review was requested for this pull request.

Comment /oz-review on this pull request to retrigger a review (up to 3 times on the same pull request).

Powered by Oz

@warp-for-oss warp-for-oss Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Overview

This PR refactors settings registration so the macro emits per-setting metadata/callbacks and shared generic registration code handles the common SettingsManager wiring.

Concerns

  • Several added comments/doc comments describe the refactor history (for example, what the macro "used to" do or the "formerly expanded" implementation) rather than documenting the stable current-state rationale. Warp's comment guidance requires comments to avoid transformation phrasing.

Verdict

Found: 0 critical, 3 important, 0 suggestions

Request changes

Comment /oz-review on this pull request to retrigger a review (up to 3 times on the same pull request).

Powered by Oz

Comment thread crates/settings/src/registration.rs Outdated
Comment thread crates/settings/src/macros.rs Outdated
Comment thread crates/settings/src/registration.rs Outdated
Base automatically changed from david/compile-time-outline-warpui to master August 23, 2026 00:33
…c registration

The register_settings_events! macro expanded a full registration
function for every setting. Move that body into
settings::registration, where it is generic over only the settings
group and value types, so settings that share those types share one
compiled instantiation. The macro now only builds a SettingCallbacks
struct of function pointers at its expansion site, which keeps the
method resolution of the old expanded code. Emit change events through
the new SettingChangeEvent trait so define_setting! and
implement_setting_for_enum! generate one concat_idents! block per
setting instead of four.

Co-Authored-By: Warp <agent@warp.dev>
@vorporeal
vorporeal force-pushed the david/compile-time-settings-macros branch from 9ab2588 to 8a94633 Compare August 23, 2026 00:33
Co-authored-by: warp-for-oss[bot] <277970191+warp-for-oss[bot]@users.noreply.github.com>
@vorporeal
vorporeal merged commit 6a96a72 into master Aug 23, 2026
26 checks passed
@vorporeal
vorporeal deleted the david/compile-time-settings-macros branch August 23, 2026 01:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants