refactor(swift): split SwiftInterface into layered modules over SwiftDeclaration#92
Conversation
…Declaration Decompose the monolithic SwiftInterface target into a set of layered peer modules sharing a single SwiftDeclaration base model: - SwiftDeclaration - base model: TypeDefinition, Definition protocols, Names/Kinds, Extensions, and the shared SwiftIndexEvents namespace (Payload/Dispatcher/Handler/contexts) emitted by both indexer and printer. - SwiftIndexing - SwiftDeclarationIndexer plus the concrete event handler implementations (SwiftIndexEventReporter, OSLog/Console handlers) and the index configuration. - SwiftPrinting - SwiftDeclarationPrinter, the node printers/printables, and the print configuration. Depends on SwiftAttributeInference. - SwiftSpecialization - GenericSpecializer, the specialization models, and TypeDefinition's specialization behavior. The base TypeDefinition keeps only isSpecialized and metadata; the rest (specialize family, specializedChildren via @AssociatedObject, depth-limit logging via a @loggable protocol) lives here. - SwiftAttributeInference - TypeAttributeInferrer / MemberAttributeInferrer. - SwiftInterface - thin SwiftInterfaceBuilder orchestrator on top. Printing and indexing are peers - neither depends on the other. Per-target test targets mirror the module split (SwiftPrintingTests, SwiftIndexingTests, SwiftSpecializationTests, SwiftAttributeInferenceTests, SwiftInterfaceTests). Renames: - SwiftInterfaceIndexer -> SwiftDeclarationIndexer - SwiftInterfacePrinter -> SwiftDeclarationPrinter - SwiftInterfaceEvents -> SwiftIndexEvents - SwiftInterfacePrintConfiguration -> SwiftDeclarationPrintConfiguration - SwiftInterfaceMemberSortOrder -> SwiftDeclarationMemberSortOrder SwiftInterfaceBuilder and the .swiftinterface file types (SwiftInterfaceFile, SwiftInterfaceParser, ...) keep their names as legitimate SwiftInterface concepts. swift build / --build-tests green; 156 Swift* unit tests pass.
There was a problem hiding this comment.
Code Review
This pull request modularizes the monolithic SwiftInterface target into several smaller, focused targets: SwiftDeclaration, SwiftIndexing, SwiftAttributeInference, SwiftPrinting, and SwiftSpecialization. This refactoring involves renaming key classes and configurations (e.g., SwiftInterfaceIndexer to SwiftDeclarationIndexer), adjusting access levels to package, and moving runtime specialization logic out of the base TypeDefinition model using associated objects. The review feedback identifies two important issues: missing dependencies (MemberwiseInit and SwiftStdlibToolbox) in Package.swift for the new targets, and performance overhead from storing a Swift Array directly as an associated object in TypeDefinition+Specialization.swift, which can be optimized by wrapping it in a reference-type box.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
| static let SwiftDeclaration = Target.target( | ||
| name: "SwiftDeclaration", | ||
| dependencies: [ | ||
| .product(.MachOKit), | ||
| .product(.MachOObjCSection), | ||
| .product(.Semantic), | ||
| .product(.Demangling), | ||
| .product(name: "FoundationToolbox", package: "FrameworkToolbox"), | ||
| .target(.MachOSwiftSection), | ||
| .target(.SwiftInspection), | ||
| .target(.SwiftDump), | ||
| .target(.Utilities), | ||
| ] |
There was a problem hiding this comment.
The newly introduced SwiftDeclaration target imports MemberwiseInit and SwiftStdlibToolbox (e.g., in SwiftIndexEvents.swift), but these are not declared in its dependencies in Package.swift. This will cause compilation failures under strict dependency checking.
Additionally, SwiftIndexing and SwiftPrinting targets also import MemberwiseInit and/or SwiftStdlibToolbox but lack them in their dependencies. Please ensure these dependencies are added to all targets that import them.
| static let SwiftDeclaration = Target.target( | |
| name: "SwiftDeclaration", | |
| dependencies: [ | |
| .product(.MachOKit), | |
| .product(.MachOObjCSection), | |
| .product(.Semantic), | |
| .product(.Demangling), | |
| .product(name: "FoundationToolbox", package: "FrameworkToolbox"), | |
| .target(.MachOSwiftSection), | |
| .target(.SwiftInspection), | |
| .target(.SwiftDump), | |
| .target(.Utilities), | |
| ] | |
| static let SwiftDeclaration = Target.target( | |
| name: "SwiftDeclaration", | |
| dependencies: [ | |
| .product(.MachOKit), | |
| .product(.MachOObjCSection), | |
| .product(.Semantic), | |
| .product(.Demangling), | |
| .product(name: "FoundationToolbox", package: "FrameworkToolbox"), | |
| .product(name: "SwiftStdlibToolbox", package: "FrameworkToolbox"), | |
| .product(name: "MemberwiseInit", package: "swift-memberwise-init"), | |
| .target(.MachOSwiftSection), | |
| .target(.SwiftInspection), | |
| .target(.SwiftDump), | |
| .target(.Utilities), | |
| ] | |
| ) |
| /// Associated-object backing for `specializedChildren`. Mutated only | ||
| /// within this file (the `specialize(...)` family appends to it). | ||
| @AssociatedObject(.retain(.nonatomic)) | ||
| private var _specializedChildren: [TypeDefinition] = [] |
There was a problem hiding this comment.
Storing a Swift Array (struct) directly as an associated object using @AssociatedObject with .retain incurs Objective-C bridging overhead (copying and wrapping/unwrapping elements) on every read and write. Furthermore, mutating it via append copies the entire array (
Wrapping the array in a simple reference-type box (SpecializedChildrenBox) allows specializedChildren and the specialize methods to append to the box's children.
| /// Associated-object backing for `specializedChildren`. Mutated only | |
| /// within this file (the `specialize(...)` family appends to it). | |
| @AssociatedObject(.retain(.nonatomic)) | |
| private var _specializedChildren: [TypeDefinition] = [] | |
| private final class SpecializedChildrenBox { | |
| var children: [TypeDefinition] = [] | |
| } | |
| @AssociatedObject(.retain(.nonatomic)) | |
| private var _specializedChildrenBox: SpecializedChildrenBox? |
There was a problem hiding this comment.
Pull request overview
This PR refactors the Swift interface tooling by decomposing the previous monolithic SwiftInterface implementation into layered modules centered around a shared SwiftDeclaration model, keeping indexing and printing as peers and moving specialization logic into a dedicated module.
Changes:
- Introduces
SwiftDeclarationas the shared declaration model (names/kinds/definitions + sharedSwiftIndexEvents). - Splits responsibilities into new peer modules (
SwiftIndexing,SwiftPrinting,SwiftSpecialization,SwiftAttributeInference) and updatesSwiftInterfaceto be a thin orchestrator. - Updates package/test targets and renames public/SPI entry points (
SwiftDeclarationIndexer,SwiftDeclarationPrinter,SwiftIndexEvents, configurations/sort orders).
Reviewed changes
Copilot reviewed 57 out of 73 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| Tests/SwiftSpecializationTests/NestedSpecializationDepthLimitTests.swift | Updates imports for split modules |
| Tests/SwiftSpecializationTests/GenericTypeNameSubstitutionTests.swift | Updates imports for split modules |
| Tests/SwiftSpecializationTests/GenericSpecializationTests.swift | Updates imports + rename to SwiftDeclarationIndexer |
| Tests/SwiftPrintingTests/NodePrinterTests.swift | Updates imports for split modules |
| Tests/SwiftInterfaceTests/SymbolTestsCoreE2ETests.swift | Uses SwiftDeclarationMemberSortOrder |
| Tests/SwiftInterfaceTests/Snapshots/SymbolTestsCoreInterfaceSnapshotTests.swift | Updates imports for split modules |
| Tests/SwiftIndexingTests/SymbolTestsCoreIntegrationTests.swift | Renames indexer types + updates comment |
| Tests/SwiftAttributeInferenceTests/TypeAttributeInferrerTests.swift | Imports SwiftDeclaration and SwiftAttributeInference |
| Tests/SwiftAttributeInferenceTests/MemberAttributeInferrerTests.swift | Imports SwiftDeclaration and SwiftAttributeInference |
| Tests/IntegrationTests/SwiftInterface/SwiftInterfaceIndexerTests.swift | Renames integration test to SwiftDeclarationIndexer usage |
| Tests/IntegrationTests/SwiftInterface/SwiftInterfaceBuilderTests.swift | Updates imports for split modules |
| Sources/SwiftSpecialization/TypeDefinition+Specialization.swift | Moves specialization behavior onto TypeDefinition via extension |
| Sources/SwiftSpecialization/SpecializationValidation.swift | Adds selection validation result model |
| Sources/SwiftSpecialization/SpecializationSelection.swift | Adds selection model + builder helpers |
| Sources/SwiftSpecialization/SpecializationResult.swift | Adds runtime specialization result wrapper |
| Sources/SwiftSpecialization/SpecializationRequest.swift | Adds SwiftDeclaration import for request types |
| Sources/SwiftSpecialization/NestedSpecializing.swift | Adds specialization-engine abstraction protocol |
| Sources/SwiftSpecialization/GenericSpecializer+NestedSpecializing.swift | Declares GenericSpecializer conformance |
| Sources/SwiftSpecialization/GenericSpecializer.swift | Renames indexer dependency type to SwiftDeclarationIndexer |
| Sources/SwiftSpecialization/ConformanceProvider.swift | Updates conformance provider to new indexer naming |
| Sources/SwiftPrinting/SwiftDeclarationPrinter.swift | Renames printer + updates events/config types |
| Sources/SwiftPrinting/SwiftDeclarationPrintConfiguration.swift | Introduces printer configuration + member sort order |
| Sources/SwiftPrinting/SemanticExtensions/SemanticComponents.swift | Adjusts access levels and adds SwiftDeclaration import |
| Sources/SwiftPrinting/NodePrinter/VariableNodePrinter.swift | Adds SwiftDeclaration import |
| Sources/SwiftPrinting/NodePrinter/TypeNodePrinter.swift | Adds SwiftDeclaration import |
| Sources/SwiftPrinting/NodePrinter/SubscriptNodePrinter.swift | Adds SwiftDeclaration import |
| Sources/SwiftPrinting/NodePrinter/FunctionNodePrinter.swift | Adds SwiftDeclaration import |
| Sources/SwiftPrinting/NodePrintables/TypeNodePrintable.swift | Adds SwiftDeclaration import |
| Sources/SwiftPrinting/NodePrintables/NodePrintableDelegate.swift | Adds SwiftDeclaration import |
| Sources/SwiftPrinting/NodePrintables/NodePrintable.swift | Adds SwiftDeclaration import |
| Sources/SwiftPrinting/NodePrintables/InterfaceNodePrintable.swift | Adds SwiftDeclaration import |
| Sources/SwiftPrinting/NodePrintables/FunctionTypeNodePrintable.swift | Adds SwiftDeclaration import |
| Sources/SwiftPrinting/NodePrintables/DependentGenericNodePrintable.swift | Adds SwiftDeclaration import |
| Sources/SwiftPrinting/NodePrintables/BoundGenericNodePrintable.swift | Adds SwiftDeclaration import |
| Sources/SwiftInterface/SwiftInterfaceBuilderOpaqueTypeProvider.swift | Updates imports to new modules |
| Sources/SwiftInterface/SwiftInterfaceBuilderExtraDataProvider.swift | Updates imports to new modules |
| Sources/SwiftInterface/SwiftInterfaceBuilderDependencies.swift | Updates imports to new modules |
| Sources/SwiftInterface/SwiftInterfaceBuilderConfiguration.swift | Switches to SwiftDeclarationIndexConfiguration / SwiftDeclarationPrintConfiguration |
| Sources/SwiftInterface/SwiftInterfaceBuilder.swift | Uses new indexer/printer/events types |
| Sources/SwiftInterface/DependencyPath.swift | Updates imports to new modules |
| Sources/SwiftIndexing/SymbolIndexStoreKind+TypeKind.swift | Moves SPI mapping into SwiftIndexing |
| Sources/SwiftIndexing/SwiftIndexEventsHandlers.swift | Updates handler protocol/types to SwiftIndexEvents |
| Sources/SwiftIndexing/SwiftIndexEventReporter.swift | Renames reporter + updates event payload type |
| Sources/SwiftIndexing/SwiftDeclarationIndexer.swift | Renames indexer + migrates configuration/events types |
| Sources/SwiftIndexing/SwiftDeclarationIndexConfiguration.swift | Introduces index configuration type |
| Sources/SwiftDeclaration/Extensions.swift | Adjusts access levels; moves symbol-kind mapping out |
| Sources/SwiftDeclaration/Events/SwiftIndexEvents.swift | Renames event namespace + adds memberwise inits |
| Sources/SwiftDeclaration/Components/Names/TypeName.swift | Adds TypeName definition type |
| Sources/SwiftDeclaration/Components/Names/ProtocolName.swift | Adds ProtocolName definition type |
| Sources/SwiftDeclaration/Components/Names/ExtensionName.swift | Adjusts access level for isProtocol |
| Sources/SwiftDeclaration/Components/Names/DefinitionName.swift | Adds shared DefinitionName protocol |
| Sources/SwiftDeclaration/Components/Kinds/TypeKind.swift | Adds TypeKind enum |
| Sources/SwiftDeclaration/Components/Kinds/FunctionKind.swift | Adds FunctionKind enum |
| Sources/SwiftDeclaration/Components/Kinds/ExtensionKind.swift | Adds ExtensionKind enum |
| Sources/SwiftDeclaration/Components/Kinds/AccessorKind.swift | Adds AccessorKind enum + helper |
| Sources/SwiftDeclaration/Components/Definitions/VariableDefinition.swift | Adds VariableDefinition model |
| Sources/SwiftDeclaration/Components/Definitions/TypeDefinition.swift | Removes specialization behaviors; tightens access levels |
| Sources/SwiftDeclaration/Components/Definitions/SubscriptDefinition.swift | Adds SubscriptDefinition model |
| Sources/SwiftDeclaration/Components/Definitions/ProtocolDefinition.swift | Tightens access levels for internal helpers/state |
| Sources/SwiftDeclaration/Components/Definitions/OrderedMember.swift | Tightens access level of sorting helpers |
| Sources/SwiftDeclaration/Components/Definitions/FunctionDefinition.swift | Adds FunctionDefinition model |
| Sources/SwiftDeclaration/Components/Definitions/FieldDefinition.swift | Adds FieldDefinition + FieldFlags |
| Sources/SwiftDeclaration/Components/Definitions/ExtensionDefinition.swift | Tightens access levels on mutable state |
| Sources/SwiftDeclaration/Components/Definitions/DefinitionBuilder.swift | Makes builder package and exports needed funcs |
| Sources/SwiftDeclaration/Components/Definitions/Definition+.swift | Adds shared member-symbol plumbing helpers |
| Sources/SwiftDeclaration/Components/Definitions/Definition.swift | Makes MutableDefinition package |
| Sources/SwiftDeclaration/Components/Definitions/Accessor.swift | Adds Accessor and AccessorRepresentable |
| Sources/SwiftAttributeInference/TypeAttributeInferrer.swift | Updates imports to use SwiftDeclaration |
| Sources/SwiftAttributeInference/MemberAttributeInferrer.swift | Updates imports to use SwiftDeclaration |
| Sources/swift-section/Commands/InterfaceCommand.swift | Updates imports to new modules |
| Sources/MachOTestingSupport/GenericSpecializationTestingEnvironment.swift | Renames indexer types used in test environment |
| Sources/MachOCaches/SharedCache.swift | Updates comment reference to new indexer name |
| Package.swift | Adds new targets/products and rewires dependencies/tests |
Comments suppressed due to low confidence (1)
Sources/SwiftIndexing/SwiftIndexEventsHandlers.swift:12
- Default OSLog subsystem/category strings still reference the old
SwiftInterfacenaming ("com.MxIris.MachOSwiftSection.SwiftInterface" / "SwiftInterfaceBuilder"). After the module split/renames, this will fragment logs across subsystems and make it harder to filter SwiftIndexing events consistently.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| /// Abstraction over the generic-specialization engine, declared in the base | ||
| /// declaration model so `TypeDefinition` can drive nested-child derivation | ||
| /// without depending on `SwiftIndexing` — where the concrete | ||
| /// `GenericSpecializer` lives, coupled to `SwiftDeclarationIndexer`. The | ||
| /// engine conforms to this protocol in `SwiftIndexing`, keeping `SwiftIndexing` | ||
| /// and `SwiftPrinting` peers that both sit above this base module. |
| /// legitimate nesting. Hitting it is a diagnostic event, not a normal | ||
| /// outcome: the `logger` below (subsystem | ||
| /// `com.machoswiftsection.swift-interface`, category | ||
| /// `TypeDefinition.nestedSpecialization`) carries the warning emitted | ||
| /// when the guard trips. |
| /// arguments). The recursion is bounded by | ||
| /// `nestedSpecializationDepthLimit`; hitting it logs an `os_log` | ||
| /// warning under the `com.machoswiftsection.swift-interface` subsystem | ||
| /// and truncates the subtree. |
… to concrete type The module split introduced a NestedSpecializing protocol so TypeDefinition's nested-child derivation could drive the engine without a concrete dependency. Since the specialize(...) extension, GenericSpecializer, and the conformance all landed in the same SwiftSpecialization module, the indirection no longer buys any decoupling. Reference GenericSpecializer<MachOImage> directly and drop the protocol and its conformance file. Call sites revert to the engine's default candidateOptions/metadataRequest, matching the pre-protocol behavior. Also fix stale doc comments referencing a nonexistent image:/machOImage parameter.
Update the module dependency hierarchy and Core Modules sections to reflect the SwiftDeclaration / SwiftIndexing / SwiftPrinting / SwiftSpecialization / SwiftAttributeInference layering, and repoint the GenericSpecializer notes at the SwiftSpecialization module (dropping the dead IMPLEMENTATION_PLAN.md reference). Also remove a leftover import SwiftInterface in NestedSpecializationDepthLimitTests.
The 'Verify matching changelog exists' step required a Changelogs/<version>.md for every BundledVersion.value, including pre-release bumps like 0.12.0-beta.4. Beta/rc versions don't ship changelogs, so the check failed on every PR carrying such a version (and on main itself). Skip the changelog requirement when the version carries a SemVer pre-release suffix (contains '-'); stable releases are still required to have a matching changelog.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 57 out of 73 changed files in this pull request and generated 1 comment.
Comments suppressed due to low confidence (2)
Sources/SwiftIndexing/SwiftIndexEventsHandlers.swift:11
OSLogEventHandler's default subsystem/category still reference the pre-refactorSwiftInterface/SwiftInterfaceBuilder, which is misleading now that events areSwiftIndexEventsand the handler lives inSwiftIndexing. Updating the defaults makes log filtering/grouping clearer.
Sources/SwiftPrinting/SwiftDeclarationPrinter.swift:440- Identifier spelling:
dispatchingCatchedThrowing/printCatchedThrowinguse “Catched” (non-standard) instead of “Caught”. Renaming improves clarity/searchability, but requires updating call sites (e.g.SwiftInterfaceBuilder).
| switch type { | ||
| case .struct: isCompatibleKind = metadata.isStruct | ||
| case .enum: isCompatibleKind = metadata.isEnum || metadata.isOptional | ||
| case .class: isCompatibleKind = metadata.isClass |
Summary
Decompose the monolithic
SwiftInterfacetarget into a set of layered peer modules sharing a singleSwiftDeclarationbase model:TypeDefinition,Definitionprotocols, Names/Kinds, Extensions, and the sharedSwiftIndexEventsnamespace (Payload/Dispatcher/Handler/contexts) emitted by both indexer and printer.SwiftDeclarationIndexerplus the concrete event handler implementations (SwiftIndexEventReporter, OSLog/Console handlers) and the index configuration.SwiftDeclarationPrinter, the node printers/printables, and the print configuration. Depends onSwiftAttributeInference.GenericSpecializer, the specialization models, andTypeDefinition's specialization behavior. The baseTypeDefinitionkeeps onlyisSpecializedand metadata; the rest (specialize family,specializedChildrenvia@AssociatedObject, depth-limit logging via a@Loggableprotocol) lives here.TypeAttributeInferrer/MemberAttributeInferrer.SwiftInterfaceBuilderorchestrator on top.Printing and indexing are peers — neither depends on the other. Per-target test targets mirror the module split (
SwiftPrintingTests,SwiftIndexingTests,SwiftSpecializationTests,SwiftAttributeInferenceTests,SwiftInterfaceTests).Renames
SwiftInterfaceIndexer→SwiftDeclarationIndexerSwiftInterfacePrinter→SwiftDeclarationPrinterSwiftInterfaceEvents→SwiftIndexEventsSwiftInterfacePrintConfiguration→SwiftDeclarationPrintConfigurationSwiftInterfaceMemberSortOrder→SwiftDeclarationMemberSortOrderSwiftInterfaceBuilderand the.swiftinterfacefile types (SwiftInterfaceFile,SwiftInterfaceParser, ...) keep their names as legitimate SwiftInterface concepts.Testing
swift build/--build-testsgreen; 156 Swift* unit tests pass.