Skip to content

refactor(swift): split SwiftInterface into layered modules over SwiftDeclaration#92

Merged
Mx-Iris merged 4 commits into
mainfrom
refactor/split-swift-interface-modules
Jun 16, 2026
Merged

refactor(swift): split SwiftInterface into layered modules over SwiftDeclaration#92
Mx-Iris merged 4 commits into
mainfrom
refactor/split-swift-interface-modules

Conversation

@Mx-Iris

@Mx-Iris Mx-Iris commented Jun 16, 2026

Copy link
Copy Markdown
Member

Summary

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.
  • SwiftIndexingSwiftDeclarationIndexer plus the concrete event handler implementations (SwiftIndexEventReporter, OSLog/Console handlers) and the index configuration.
  • SwiftPrintingSwiftDeclarationPrinter, the node printers/printables, and the print configuration. Depends on SwiftAttributeInference.
  • SwiftSpecializationGenericSpecializer, 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.
  • SwiftAttributeInferenceTypeAttributeInferrer / 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

  • SwiftInterfaceIndexerSwiftDeclarationIndexer
  • SwiftInterfacePrinterSwiftDeclarationPrinter
  • SwiftInterfaceEventsSwiftIndexEvents
  • SwiftInterfacePrintConfigurationSwiftDeclarationPrintConfiguration
  • SwiftInterfaceMemberSortOrderSwiftDeclarationMemberSortOrder

SwiftInterfaceBuilder and the .swiftinterface file types (SwiftInterfaceFile, SwiftInterfaceParser, ...) keep their names as legitimate SwiftInterface concepts.

Testing

swift build / --build-tests green; 156 Swift* unit tests pass.

…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.
Copilot AI review requested due to automatic review settings June 16, 2026 12:08

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

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.

Comment thread Package.swift
Comment on lines +440 to +452
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),
]

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

high

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.

Suggested change
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),
]
)

Comment on lines +21 to +24
/// Associated-object backing for `specializedChildren`. Mutated only
/// within this file (the `specialize(...)` family appends to it).
@AssociatedObject(.retain(.nonatomic))
private var _specializedChildren: [TypeDefinition] = []

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

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 ($O(N)$ complexity).

Wrapping the array in a simple reference-type box (SpecializedChildrenBox) allows $O(1)$ in-place mutation and completely avoids bridging overhead. Remember to update the getter of specializedChildren and the specialize methods to append to the box's children.

Suggested change
/// 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?

Copilot AI 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.

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 SwiftDeclaration as the shared declaration model (names/kinds/definitions + shared SwiftIndexEvents).
  • Splits responsibilities into new peer modules (SwiftIndexing, SwiftPrinting, SwiftSpecialization, SwiftAttributeInference) and updates SwiftInterface to 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 SwiftInterface naming ("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.

Comment on lines +3 to +8
/// 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.
Comment on lines +76 to +80
/// 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.
Comment on lines +160 to +163
/// 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.
Mx-Iris added 3 commits June 16, 2026 20:58
… 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.
Copilot AI review requested due to automatic review settings June 16, 2026 13:03

Copilot AI 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.

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-refactor SwiftInterface / SwiftInterfaceBuilder, which is misleading now that events are SwiftIndexEvents and the handler lives in SwiftIndexing. Updating the defaults makes log filtering/grouping clearer.
    Sources/SwiftPrinting/SwiftDeclarationPrinter.swift:440
  • Identifier spelling: dispatchingCatchedThrowing / printCatchedThrowing use “Catched” (non-standard) instead of “Caught”. Renaming improves clarity/searchability, but requires updating call sites (e.g. SwiftInterfaceBuilder).

Comment on lines +365 to +368
switch type {
case .struct: isCompatibleKind = metadata.isStruct
case .enum: isCompatibleKind = metadata.isEnum || metadata.isOptional
case .class: isCompatibleKind = metadata.isClass
@Mx-Iris Mx-Iris merged commit 7de876e into main Jun 16, 2026
2 of 3 checks passed
@Mx-Iris Mx-Iris deleted the refactor/split-swift-interface-modules branch June 24, 2026 01:07
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.

2 participants