Auto-conform @ExpoModule classes to AnyModule#5
Draft
tsapeta wants to merge 2 commits into@tsapeta/expo-module-inheritancefrom
Draft
Auto-conform @ExpoModule classes to AnyModule#5tsapeta wants to merge 2 commits into@tsapeta/expo-module-inheritancefrom
@ExpoModule classes to AnyModule#5tsapeta wants to merge 2 commits into@tsapeta/expo-module-inheritancefrom
Conversation
`@ExpoModule` now also conforms to `ExtensionMacro` and emits an
`extension MyModule: AnyModule {}` when the class doesn't already
inherit from `Module`, `BaseModule`, or `AnyModule`. This unblocks
`@ExpoModule` for classes that need a different concrete superclass
(e.g. an existing app-specific base class) — the conformance comes
from the macro instead of being baked into the declaration.
Replaces the inheritance-required diagnostic introduced earlier:
the macro is now permissive about the inheritance line. If the
class doesn't satisfy `AnyModule`'s remaining requirements through
some other mechanism (its own storage and `init(appContext:)`), the
type checker still surfaces a clear error pointing at the generated
extension.
The macro skips emission when the class literally inherits from
`Module`, `BaseModule`, or `AnyModule` — those names already supply
the conformance, and a redundant extension would error.
`@ExpoModule` now fills in everything `BaseModule` used to provide when the class doesn't inherit from `Module` or `BaseModule`: - `public weak var appContext: AppContext?` — the module's app-context storage, declared `weak` to mirror `BaseModule`. - `public required init(appContext: AppContext)` — the protocol-required initializer, storing the context into the synthesized property. - `@ModuleDefinitionBuilder` stamped on `func definition() -> ModuleDefinition` so the result-builder application is explicit on the user's declaration rather than relying on Swift's protocol-requirement inference. The macro skips emission when the user provides their own `appContext` property, their own `init(appContext:)`, or already stamped `@ModuleDefinitionBuilder` on `definition()` themselves. The emission order in the expansion is `appContext` -> `init(appContext:)` -> `_exposedDefinition()` so storage/init read first when scanning the generated members.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Stacked on top of #4. Two commits:
Auto-conform
@ExpoModuleclasses toAnyModule— emitsextension MyModule: AnyModule {}when the class doesn't already inherit fromModule,BaseModule, orAnyModule. Replaces the inheritance-required diagnostic from Diagnose missingModuleinheritance on@ExpoModuleclasses #4 with permissive expansion.Synthesize
appContext,init(appContext:), and@ModuleDefinitionBuilder— the macro now fills in everythingBaseModuleused to provide, so a@ExpoModuleclass can stand on its own without inheriting fromBaseModule. Skips emission when the user provided any of these themselves.Together these two steps unblock
@ExpoModulefor classes that need to author the module surface without committing to a specific superclass.What gets skipped, and when
extension: AnyModuleappContextinit(appContext:)@ModuleDefinitionBuilder: ModuleBaseModuleprovides)BaseModuleprovides): BaseModuleBaseModule): AnyModule: SomeOtherBaseappContextinit(appContext:)@ModuleDefinitionBuilderTest plan
swift testpasses — 27 cases total (8 new across the two commits).@ExpoModulewithout: Module, the iOS build succeeds and JS calls round-trip.: Moduleexplicitly, no "redundant conformance" or duplicate-member errors appear.appContext/init(appContext:)/@ModuleDefinitionBuilderdoesn't get a duplicate from the macro.