feat(MachOSwiftSection): introduce ReadingContext API#84
Conversation
Scopes a focused completion pass to add ReadingContext-based overloads to the ~45 model files in Sources/MachOSwiftSection/Models/ that currently expose only MachO and InProcess APIs. Adds a single ReadingContext extension `runtimePointer(at:)` to express runtime-pointer-returning methods (e.g. `metadataAccessorFunction`) under the unified abstraction.
Implementation plan for the design doc at docs/superpowers/specs/2026-05-02-reading-context-api-design.md. Twelve tasks: one infrastructure (runtimePointer extension), nine content batches (per sub-directory), and two wrap-up tasks (ContextWrapper.forContextDescriptorWrapper, partial-file audit).
Default returns nil. MachOContext returns machO.ptr + address when the underlying reader is a MachOImage; InProcessContext returns the address itself. Enables runtime-pointer-returning methods (e.g. metadataAccessorFunction) to be expressed under the unified ReadingContext abstraction without per-call type dispatch.
Mirror the MachO init(descriptor:in:) overloads on AnonymousContext, ModuleContext, and ExtensionContext under the ReadingContext abstraction.
Mirror the MachO overloads on Class, ClassDescriptor, the AnyClassMetadata and FinalClassMetadata protocols, and the Method*Descriptor types. Call sites pass the context through to nested methods so the unified path is end-to-end.
Mirror init(descriptor:in:) and metadata helpers on Enum, Struct, EnumMetadataProtocol, StructMetadataProtocol, and MultiPayloadEnumDescriptor.
…tors Mirror MachO overloads on TypeContextDescriptor, TypeContextWrapper, TypeReference, and ValueMetadataProtocol. Add the missing fieldDescriptor(in:context:) and metadataAccessorFunction(in:context:) overloads on TypeContextDescriptorProtocol — the latter uses the new runtimePointer(at:) extension to return the function pointer for InProcess and MachOImage contexts and nil for MachOFile. Also retarget EnumMetadataProtocol.enumDescriptor and StructMetadataProtocol.structDescriptor to call descriptor(in:context:) now that the helper exists.
…nce types Mirror MachO overloads on Protocol, ProtocolDescriptor, ProtocolDescriptorRef, ProtocolRecord, ProtocolRequirement, ResilientWitness, GlobalActorReference, ProtocolConformance, and ProtocolConformanceDescriptor. Also adds GenericRequirement.init<Context> and ObjCProtocolPrefix.name<Context> upfront, since Protocol.init<Context> and ProtocolDescriptorRef.name<Context> require them. (GenericRequirement was scheduled for Task 8 but is needed for Task 7 to compile.)
…ociated-type Mirror MachO overloads on FieldDescriptor, FieldRecord, and the AssociatedType family. GenericRequirement.init<Context> was added as a prerequisite in the preceding protocol/conformance batch, so this batch covers only the remaining field/associated-type files.
…/wrapper Mirror the existing MachO-parameterized overloads on MetadataProtocol and MetadataWrapper with sibling <Context: ReadingContext>(in:) overloads. New methods live in `// MARK: - ReadingContext Support` extensions at the bottom of each file. MetadataProtocol gains: - asMetadataWrapper(in: Context) - asMetadata(in: Context) - asFullMetadata(in: Context) - valueWitnesses(in: Context) - typeLayout(in: Context) - typeContextDescriptorWrapper(in: Context) MetadataWrapper gains: - valueWitnessTable(in: Context) - static resolve(at: Context.Address, in: Context) The static resolve takes Context.Address directly (not an Int offset), since the caller already produces a Context-native address. Includes two small prerequisite mirrors (originally planned for Task 10) that typeContextDescriptorWrapper<Context> depends on: - ForeignClassMetadata.classDescriptor(in: Context) - ForeignReferenceTypeMetadata.classDescriptor(in: Context)
…a types Mirror MachO overloads on ExistentialTypeMetadata, TupleTypeMetadata, OpaqueType, BuiltinType, and BuiltinTypeDescriptor. ForeignClassMetadata.classDescriptor and ForeignReferenceTypeMetadata.classDescriptor were added as prerequisites in the preceding Metadata batch.
…ingContext Add parent(in:context:) on ContextProtocol and ContextWrapper, and the forContextDescriptorWrapper(_:in:context:) static factory on ContextWrapper. These three methods were deferred from earlier batches because forContextDescriptorWrapper(_:in:context:) depends on every concrete Context type having an init(descriptor:in:context:) overload — and those landed across Tasks 2, 4, 5, 6, and 7. Now that all dependencies exist, this commit closes the dependency and completes the parent traversal API under the unified ReadingContext abstraction.
Audit pass over the 15 files that previously had partial ReadingContext coverage. Adds the few overloads that were missing relative to each file's MachO API surface.
…is MachO-only implementationAddress(in:) is a debug formatter built on MachORepresentableWithCache.addressString(forOffset:) — a MachO display helper with no counterpart on ReadingContext. Document the deliberate omission in source so future audits do not re-flag it.
…pleted Task 3 (ContextDescriptor batch) was bundled with Task 11 in commit d5d1d74; update the plan checkboxes to reflect the completed state.
Spec describes a four-pillar test system for MachOSwiftSection/Models/: - MachOSwiftSectionFixtureTests base (dlopen + MachOFile/MachOImage/InProcess) - Per-method @test suites mirroring Models/ structure - baseline-generator executable producing literal Swift expected values - Coverage invariant via SwiftSyntax static scan + Suite reflection Strategy: cross-reader equality + full ABI literal assertions, baselines generated once and frozen in git, regenerated on toolchain/fixture churn.
There was a problem hiding this comment.
Code Review
This pull request implements comprehensive ReadingContext API coverage across the MachOSwiftSection models, providing a unified abstraction for reading Swift metadata from in-process memory and Mach-O files. It introduces the runtimePointer(at:) extension to support methods returning runtime pointers and includes design and implementation plans. Feedback points out a logic error in TypeContextWrapper.swift where return keywords are missing in a switch statement, and identifies several instances of a typo in the moduleContextDescriptor method name.
| switch typeContextDescriptorWrapper { | ||
| case .enum(let enumDescriptor): | ||
| try .enum(.init(descriptor: enumDescriptor, in: context)) | ||
| case .struct(let structDescriptor): | ||
| try .struct(.init(descriptor: structDescriptor, in: context)) | ||
| case .class(let classDescriptor): | ||
| try .class(.init(descriptor: classDescriptor, in: context)) | ||
| } |
There was a problem hiding this comment.
The switch statement is missing return keywords for each case. While Swift 5.9+ supports switch expressions, they must be used in a context that expects a value (like a return statement or assignment) to function as an implicit return for the method. For consistency with ContextWrapper.forContextDescriptorWrapper and clarity, explicit return statements should be added.
|
|
||
| func genericContext<Context: ReadingContext>(in context: Context) throws -> GenericContext? | ||
| func parent<Context: ReadingContext>(in context: Context) throws -> SymbolOrElement<ContextDescriptorWrapper>? | ||
| func moduleContextDesciptor<Context: ReadingContext>(in context: Context) throws -> (any ModuleContextDescriptorProtocol)? |
| return try GenericContext(contextDescriptor: self, in: context) | ||
| } | ||
|
|
||
| public func moduleContextDesciptor<Context: ReadingContext>(in context: Context) throws -> (any ModuleContextDescriptorProtocol)? { |
| } | ||
|
|
||
| public func isCImportedContextDescriptor<Context: ReadingContext>(in context: Context) throws -> Bool { | ||
| guard let moduleContextDescriptor = try moduleContextDesciptor(in: context) else { return false } |
There was a problem hiding this comment.
Pull request overview
This PR completes the ReadingContext adoption across MachOSwiftSection/Models by adding <Context: ReadingContext>(in:) overloads that mirror existing MachO/InProcess APIs, plus a small runtimePointer(at:) capability to express runtime-pointer-returning methods (e.g. metadata accessors). It also adds design/plan documentation (including fixture-based test coverage notes) to guide follow-on testing work.
Changes:
- Add
ReadingContext.runtimePointer(at:)(defaultnil) with overrides forMachOContext(MachOImage-only) andInProcessContext. - Add missing
ReadingContextoverloads across many model types/descriptors/wrappers so context can flow end-to-end. - Add/expand internal design + implementation plan docs for ReadingContext coverage and fixture-based test coverage.
Reviewed changes
Copilot reviewed 57 out of 57 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| docs/superpowers/specs/2026-05-03-machoswift-section-fixture-tests-design.md | New spec describing fixture-based test coverage strategy for MachOSwiftSection. |
| docs/superpowers/specs/2026-05-02-reading-context-api-design.md | New spec for completing ReadingContext API coverage + runtimePointer(at:). |
| docs/superpowers/plans/2026-05-02-reading-context-api.md | New detailed implementation plan for rolling out ReadingContext overloads. |
| Sources/MachOSwiftSection/Models/Type/ValueMetadataProtocol.swift | Add descriptor(in: ReadingContext) overload. |
| Sources/MachOSwiftSection/Models/Type/TypeReference.swift | Add resolve(at:in: ReadingContext) overload. |
| Sources/MachOSwiftSection/Models/Type/TypeContextWrapper.swift | Add ReadingContext factory for TypeContextWrapper. |
| Sources/MachOSwiftSection/Models/Type/TypeContextDescriptorProtocol.swift | Add fieldDescriptor(in:) + metadataAccessorFunction(in:) for ReadingContext. |
| Sources/MachOSwiftSection/Models/Type/TypeContextDescriptor.swift | Add kind-specific descriptor accessors for ReadingContext. |
| Sources/MachOSwiftSection/Models/Type/Struct/StructMetadataProtocol.swift | Add ReadingContext descriptor + fieldOffsets helpers. |
| Sources/MachOSwiftSection/Models/Type/Struct/Struct.swift | Add ReadingContext initializer and parsing logic. |
| Sources/MachOSwiftSection/Models/Type/Enum/MultiPayloadEnumDescriptor.swift | Add ReadingContext accessors for enum descriptor data. |
| Sources/MachOSwiftSection/Models/Type/Enum/Metadata/EnumMetadataProtocol.swift | Add ReadingContext helpers for enum metadata (descriptor + payloadSize). |
| Sources/MachOSwiftSection/Models/Type/Enum/Enum.swift | Add ReadingContext initializer and parsing logic. |
| Sources/MachOSwiftSection/Models/Type/Class/Method/MethodOverrideDescriptor.swift | Add ReadingContext accessors for override descriptors. |
| Sources/MachOSwiftSection/Models/Type/Class/Method/MethodDescriptor.swift | Add ReadingContext accessor for implementation symbols. |
| Sources/MachOSwiftSection/Models/Type/Class/Method/MethodDefaultOverrideDescriptor.swift | Add ReadingContext accessors for default override descriptors. |
| Sources/MachOSwiftSection/Models/Type/Class/Metadata/FinalClassMetadataProtocol.swift | Add ReadingContext fieldOffsets + descriptor helpers. |
| Sources/MachOSwiftSection/Models/Type/Class/Metadata/AnyClassMetadataObjCInterop/AnyClassMetadataObjCInteropProtocol.swift | Add ReadingContext helpers for ObjC interop metadata. |
| Sources/MachOSwiftSection/Models/Type/Class/Metadata/AnyClassMetadata/AnyClassMetadataProtocol.swift | Add ReadingContext asFinalClassMetadata(in:). |
| Sources/MachOSwiftSection/Models/Type/Class/ClassDescriptor.swift | Add ReadingContext resilient metadata/superclass helpers. |
| Sources/MachOSwiftSection/Models/Type/Class/Class.swift | Add ReadingContext initializer and parsing logic. |
| Sources/MachOSwiftSection/Models/TupleType/TupleTypeMetadata.swift | Add ReadingContext tuple element reader. |
| Sources/MachOSwiftSection/Models/ProtocolConformance/ProtocolConformanceDescriptor.swift | Add ReadingContext descriptor/type/witness accessors. |
| Sources/MachOSwiftSection/Models/ProtocolConformance/ProtocolConformance.swift | Add ReadingContext initializer and parsing logic. |
| Sources/MachOSwiftSection/Models/ProtocolConformance/GlobalActorReference.swift | Add ReadingContext typeName(in:). |
| Sources/MachOSwiftSection/Models/Protocol/ResilientWitness.swift | Document MachO-only helper; add ReadingContext accessors. |
| Sources/MachOSwiftSection/Models/Protocol/ProtocolRequirement.swift | Add ReadingContext default-implementation symbol lookup. |
| Sources/MachOSwiftSection/Models/Protocol/ProtocolRecord.swift | Add ReadingContext protocol-descriptor resolver. |
| Sources/MachOSwiftSection/Models/Protocol/ProtocolDescriptorRef.swift | Add ReadingContext name resolution for objc/swift protocol refs. |
| Sources/MachOSwiftSection/Models/Protocol/ProtocolDescriptor.swift | Add ReadingContext associatedTypes(in:). |
| Sources/MachOSwiftSection/Models/Protocol/Protocol.swift | Add ReadingContext initializer and parsing logic. |
| Sources/MachOSwiftSection/Models/Protocol/ObjC/ObjCProtocolPrefix.swift | Add ReadingContext name(in:). |
| Sources/MachOSwiftSection/Models/OpaqueType/OpaqueType.swift | Add ReadingContext initializer and parsing logic. |
| Sources/MachOSwiftSection/Models/Module/ModuleContext.swift | Add ReadingContext initializer. |
| Sources/MachOSwiftSection/Models/Metadata/MetadataWrapper.swift | Add ReadingContext metadata wrapper resolution + VWT accessor. |
| Sources/MachOSwiftSection/Models/Metadata/MetadataProtocol.swift | Add ReadingContext metadata wrapper/metadata/full-metadata helpers. |
| Sources/MachOSwiftSection/Models/Generic/GenericRequirementDescriptor.swift | Add ReadingContext-only comparison helper used for de-duping requirements. |
| Sources/MachOSwiftSection/Models/Generic/GenericRequirement.swift | Add ReadingContext initializer. |
| Sources/MachOSwiftSection/Models/Generic/GenericContext.swift | Add ReadingContext helper to compute unique requirements. |
| Sources/MachOSwiftSection/Models/ForeignType/ForeignReferenceTypeMetadata.swift | Add ReadingContext classDescriptor(in:). |
| Sources/MachOSwiftSection/Models/ForeignType/ForeignClassMetadata.swift | Add ReadingContext classDescriptor(in:). |
| Sources/MachOSwiftSection/Models/FieldRecord/FieldRecord.swift | Add ReadingContext accessors for type/name fields. |
| Sources/MachOSwiftSection/Models/FieldDescriptor/FieldDescriptor.swift | Add ReadingContext accessors for records + mangled name. |
| Sources/MachOSwiftSection/Models/Extension/ExtensionContext.swift | Add ReadingContext initializer. |
| Sources/MachOSwiftSection/Models/ExistentialType/ExistentialTypeMetadata.swift | Add ReadingContext helpers for superclass constraint + protocols. |
| Sources/MachOSwiftSection/Models/ContextDescriptor/ContextWrapper.swift | Add ReadingContext factory + parent traversal. |
| Sources/MachOSwiftSection/Models/ContextDescriptor/ContextProtocol.swift | Add ReadingContext parent traversal helper. |
| Sources/MachOSwiftSection/Models/ContextDescriptor/ContextDescriptorProtocol.swift | Add ReadingContext requirements + implementations for module lookup / C-import checks. |
| Sources/MachOSwiftSection/Models/BuiltinType/BuiltinTypeDescriptor.swift | Add ReadingContext typeName(in:). |
| Sources/MachOSwiftSection/Models/BuiltinType/BuiltinType.swift | Add ReadingContext initializer. |
| Sources/MachOSwiftSection/Models/AssociatedType/AssociatedTypeRecord.swift | Add ReadingContext accessors for name/substituted type. |
| Sources/MachOSwiftSection/Models/AssociatedType/AssociatedTypeDescriptor.swift | Add ReadingContext accessors for type/protocol/records. |
| Sources/MachOSwiftSection/Models/AssociatedType/AssociatedType.swift | Add ReadingContext initializer. |
| Sources/MachOSwiftSection/Models/Anonymous/AnonymousContext.swift | Add ReadingContext initializer. |
| Sources/MachOReading/ReadingContext/ReadingContext.swift | Add default runtimePointer(at:) extension (returns nil). |
| Sources/MachOReading/ReadingContext/MachOContext.swift | Override runtimePointer(at:) for MachOImage-backed contexts. |
| Sources/MachOReading/ReadingContext/InProcessContext.swift | Override runtimePointer(at:) for in-process contexts. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| public func replacementMethodDescriptor<Context: ReadingContext>(in context: Context) throws -> SymbolOrElement<MethodDescriptor>? { | ||
| return try layout.replacement.resolve(at: try context.addressFromOffset(offset(of: \.original)), in: context).asOptional | ||
| } |
| func moduleContextDesciptor<Context: ReadingContext>(in context: Context) throws -> (any ModuleContextDescriptorProtocol)? | ||
| func isCImportedContextDescriptor<Context: ReadingContext>(in context: Context) throws -> Bool |
…irement Declaring runtimePointer(at:) as a protocol requirement (with the existing nil default kept in an extension) lets existential `any ReadingContext` calls dynamic-dispatch to the concrete context's override, instead of silently picking up the static default. Generic call sites are unchanged; external conformers stay non-breaking thanks to the default.
…talError MetadataWrapper.resolve previously called fatalError() when it hit .lastEnumerated, which would crash the whole process if a future Swift runtime introduced a new metadata kind. Replace with a typed MachOSwiftSectionError.unknownMetadataKind, applied to all three resolve overloads (MachO, InProcess, ReadingContext).
…scriptor
All three replacementMethodDescriptor overloads (MachO, InProcess,
ReadingContext) were resolving layout.replacement using the offset of
\.original, which reads from the wrong field given the layout's
{replacement, original, implementation} ordering.
The protocol method had a long-standing misspelling (Desciptor) that the recent ReadingContext overload propagated into the new API surface. Rename across all three overloads (MachO, InProcess, ReadingContext) plus the one call site in SnapshotDumpableTests.
TypeContextWrapper used Swift 5.9+ implicit-return switch expressions while ContextWrapper and the rest of the project use explicit return. Switch the four affected switches to explicit return for consistency.
Summary
Test plan