Skip to content

[CPP-4503] Add async builder and plugin; update tests; update stencils#923

Open
aleksey-krauchuk-gotinder wants to merge 8 commits intoTinder:mainfrom
aleksey-krauchuk-gotinder:add-async-builder
Open

[CPP-4503] Add async builder and plugin; update tests; update stencils#923
aleksey-krauchuk-gotinder wants to merge 8 commits intoTinder:mainfrom
aleksey-krauchuk-gotinder:add-async-builder

Conversation

@aleksey-krauchuk-gotinder
Copy link
Copy Markdown
Collaborator

@aleksey-krauchuk-gotinder aleksey-krauchuk-gotinder commented Mar 26, 2026

CPP-4503

Summary

Adds async overloads to AbstractBuilder and Plugin, enabling builders to await async dependencies during construction. This lays the groundwork for Swift Concurrency adoption across all Nodes.

Changes

  • Add async variants of open func build(...) to AbstractBuilder and Plugin
  • Add corresponding async variants of the public convenience methods (build(_:_:), create(state:), override())
  • Pin Mockolo to 2.5.0 in Genesis CI workflow

Why preconditionFailure instead of async-wraps-sync

An intuitive approach would be to have the async method's default implementation delegate to the sync one, so existing sync builders "just work" when called from an async context. However, Swift's overload resolution prevents this: when two methods share the same name and differ only by async, calling build(component:dynamicBuildDependency:) from within an async context always resolves to the async overload — causing infinite recursion. There's no Swift syntax to force resolution to the sync overload from an async context.

Instead, both open methods use preconditionFailure in the base class. This is safe because:

  • Existing sync builders are called through the sync path — no change in behavior
  • New async builders override the async method and are called through the async path
  • A mismatch (calling async path on a sync-only builder) triggers a clear crash with an actionable error message

Why stencils remain synchronous

The original plan was to update all Stencil templates (Builder, Interface, Plugin, Flow, and their test templates) to generate async methods by default. However, this is blocked by a regression in Mockolo 2.6.0+ (uber/mockolo#328) where #if canImport(UIKit) directives are incorrectly evaluated during parsing, causing Mockolo to skip protocols guarded by those directives (e.g. ViewControllable). This breaks mock generation in the Genesis demo project, which relies on Mockolo.

Mockolo 2.5.0 does not have this issue (it parsed all #if branches), so the Genesis CI is pinned to 2.5.0 for now. However, 2.5.0 lacks async-aware mock generation needed for async templates.

A fix is in progress upstream: uber/mockolo#346. Once merged, we can apply the async stencil changes (preserved as a patch in the repo) and remove the Mockolo version pin.

Tests

  • Added AsyncTestBuilder and AsyncTestPlugin subclasses with async build/create/override tests
  • QuickStart project still works as expected

@aleksey-krauchuk-gotinder aleksey-krauchuk-gotinder requested a review from a team as a code owner March 26, 2026 13:14
Copy link
Copy Markdown
Contributor

@tinder-emanharoutunian tinder-emanharoutunian left a comment

Choose a reason for hiding this comment

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

Nice improvement! Can we please make sure creating a QuickStart project still works as expected

@tinder-SamMarshall
Copy link
Copy Markdown
Contributor

Looks great!

@aleksey-krauchuk-gotinder
Copy link
Copy Markdown
Collaborator Author

aleksey-krauchuk-gotinder commented Mar 27, 2026

Thanks for the feedback!

Nice improvement! Can we please make sure creating a QuickStart project still works as expected

Verified using my local Nodes on this branch
Screenshot 2026-03-27 at 15 14 04
Screenshot 2026-03-27 at 15 14 38

Copy link
Copy Markdown
Contributor

@tinder-emanharoutunian tinder-emanharoutunian left a comment

Choose a reason for hiding this comment

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

Thanks for implementing and validating!

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.

5 participants