Skip to content

Make MultiProducerSingleConsumerAsyncChannel internals compatible with library evolution#426

Open
adityasingh2400 wants to merge 1 commit into
apple:mainfrom
adityasingh2400:fix-issue-405
Open

Make MultiProducerSingleConsumerAsyncChannel internals compatible with library evolution#426
adityasingh2400 wants to merge 1 commit into
apple:mainfrom
adityasingh2400:fix-issue-405

Conversation

@adityasingh2400
Copy link
Copy Markdown
Contributor

MultiProducerSingleConsumerAsyncChannel, introduced in 1.1.0, fails to compile when the consuming module is built with library evolution enabled (BUILD_LIBRARY_FOR_DISTRIBUTION=YES, i.e. -enable-library-evolution). This blocks every team that distributes a binary SDK as an XCFramework depending on swift-async-algorithms; the 1.0.x line is currently the only usable version for them.

Two classes of error come from Sources/AsyncAlgorithms/MultiProducerSingleConsumerChannel/MultiProducerSingleConsumerAsyncChannel+Internal.swift:

  • 'consume' can only be used to partially consume storage — the @inlinable mutating func methods on the non-@frozen _StateMachine struct (and the _InternalBackpressureStrategy enum) do switch consume self._state / switch consume self. Under library evolution a non-frozen type's stored properties are reached through resilient accessors, which do not vend the direct ownership consume requires.
  • initializer for class '_Storage' is '@inlinable' and must delegate to another initializer, plus the related 'let' property ... may not be initialized directly errors on the @inlinable initializers of the ~Copyable payload structs. Under library evolution an @inlinable initializer of a resilient type may only assign through a delegating self.init/self = ..., not set stored properties directly.

These reproduce on 1.1.0–1.1.3; main is still affected.

Changes:

  • Mark the internal (@usableFromInline) types whose stored storage is consumed or directly initialized in @inlinable members as @frozen, so their layout is fixed and direct storage access / consume is permitted under library evolution: _StateMachine, _State and its Channeling/SourceFinished/Finished payloads, _InternalBackpressureStrategy and its _Watermark, the ResumeElement/ResumeElementAndProducers/ResumeFailure wrappers, and SendableConsumeOnceBox. These are all already @usableFromInline internal types, so freezing them is not a public-API or source-stability change.
  • Mark _TinyArray and its Storage enum @frozen for the same reason (they back the frozen payloads).
  • Change _Storage.init(backpressureStrategy:) from @inlinable to @usableFromInline, since an @inlinable designated class initializer must delegate under library evolution and this one sets a stored property directly.

No public API changes and no behavioral changes — only resilience-attribute additions on internal types and one inlinability downgrade on an internal initializer.

Testing:

  • swift build --target AsyncAlgorithms -Xswiftc -enable-library-evolution now succeeds (it fails on main with the errors above).
  • swift build (normal, non-evolution) succeeds.
  • swift test --filter MultiProducerSingleConsumer passes — 37 tests, 0 failures.

Fixes #405.

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.

MultiProducerSingleConsumerAsyncChannel breaks library evolution (BUILD_LIBRARY_FOR_DISTRIBUTION=YES) in 1.1.x

1 participant