Skip to content

Tests: typecheck SafeDITool-generated code against its inputs#256

Merged
dfed merged 8 commits intomainfrom
claude/compile-verify-codegen-tests
Apr 20, 2026
Merged

Tests: typecheck SafeDITool-generated code against its inputs#256
dfed merged 8 commits intomainfrom
claude/compile-verify-codegen-tests

Conversation

@dfed
Copy link
Copy Markdown
Owner

@dfed dfed commented Apr 18, 2026

Summary

  • Add SafeDICompileVerifier (and SafeDIBuildArtifactLocator) that invokes swiftc -typecheck on the fixture sources plus generated output. Wire it into executeSafeDIToolTest so every test that round-trips through the generator also verifies the output compiles against the built SafeDI module and SafeDIMacros plugin.
  • Two-pass verification: inputs alone first (so fixture-Swift errors surface cleanly), then inputs plus generated output. SAFEDI_SKIP_COMPILE_CHECK=1 is an escape hatch for fast local iteration.
  • Mark tests that cannot be typechecked in isolation — cross-module placeholders, Linux-specific platform stubs, codegen with preexisting bugs — with skipCompileVerification: true and a comment explaining why. Leaves a paper trail for follow-up work.
  • Fix ~10 fixture-level issues the verifier surfaced immediately (invalid class stand-ins, missing Instantiable conformance, platform-only types standing in as protocols, etc.).

Self-review pass (commit e5b91c1)

  • Corrected the skipCompileVerification reason comment on two internal-Child tests: the verifier compiles everything in one synthetic module, so the real failure is Swift's same-module rule about public init signatures referencing internal types — not cross-module inaccessibility.

Why

Before this PR, generator regressions that produced malformed-but-plausible Swift slipped through the test suite unless they tripped an integration test. The mock output strings were compared character-for-character, but nothing confirmed that the strings were valid Swift against the rest of the module.

Test plan

  • swift test --traits sourceBuild — 841 tests pass
  • ./CLI/lint.sh
  • Codecov patch coverage — [check CI]

🤖 Generated with Claude Code

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 96a9ffa120

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread Tests/SafeDIToolTests/Helpers/SafeDICompileVerifier.swift Outdated
Comment thread Tests/SafeDIToolTests/Helpers/SafeDICompileVerifier.swift Outdated
@codecov
Copy link
Copy Markdown

codecov Bot commented Apr 18, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 100.00%. Comparing base (5f40011) to head (ddbfbd7).
⚠️ Report is 1 commits behind head on main.

Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff            @@
##              main      #256   +/-   ##
=========================================
  Coverage   100.00%   100.00%           
=========================================
  Files           41        41           
  Lines         6515      6515           
=========================================
  Hits          6515      6515           
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 8aed183888

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread Tests/SafeDIToolTests/Helpers/SafeDICompileVerifier.swift Outdated
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 709e849a27

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread Tests/SafeDIToolTests/Helpers/SafeDICompileVerifier.swift Outdated
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: fc62861318

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread Tests/SafeDIToolTests/Helpers/SafeDICompileVerifier.swift Outdated
Base automatically changed from claude/v2-beta-release-readiness-jk8KW to main April 18, 2026 19:19
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 8ae5d004c3

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread Tests/SafeDIToolTests/Helpers/SafeDICompileVerifier.swift Outdated
@dfed
Copy link
Copy Markdown
Owner Author

dfed commented Apr 18, 2026

@codex review

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: af97dc3591

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread Tests/SafeDIToolTests/Helpers/SafeDICompileVerifier.swift Outdated
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: fb78ea0051

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread Sources/SafeDICore/Generators/ScopeGenerator.swift Outdated
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 8b6b64a494

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread Tests/SafeDIToolTests/Helpers/SafeDICompileVerifier.swift Outdated
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: e7a73e895f

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread Tests/SafeDIToolTests/Helpers/SafeDIToolTestExecution.swift Outdated
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 9307cca772

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread Tests/SafeDIToolTests/Helpers/SafeDICompileVerifier.swift
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: f2444abac7

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread Sources/SafeDICore/Generators/ScopeGenerator.swift
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 29282acae2

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread Sources/SafeDICore/Generators/ScopeGenerator.swift Outdated
@dfed
Copy link
Copy Markdown
Owner Author

dfed commented Apr 19, 2026

@codex review

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 47cb8c80dc

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread Tests/SafeDIToolTests/Helpers/SafeDICompileVerifier.swift
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: deca919db6

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread Sources/SafeDICore/Generators/ScopeGenerator.swift Outdated
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: fefd28b450

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread Sources/SafeDICore/Generators/ScopeGenerator.swift Outdated
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 40e41fde8a

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread Tests/SafeDIToolTests/Helpers/SafeDIToolTestExecution.swift
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 215aacf224

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread Sources/SafeDICore/Generators/DependencyTreeGenerator.swift Outdated
Comment thread Sources/SafeDICore/Generators/DependencyTreeGenerator.swift Outdated
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 48cce11bff

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread Sources/SafeDIMacros/Macros/InstantiableMacro.swift Outdated
@dfed dfed changed the base branch from main to dfed--codegen-fixes April 19, 2026 20:18
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 3d4c12a517

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread Sources/SafeDICore/Generators/ScopeGenerator.swift
@dfed dfed force-pushed the claude/compile-verify-codegen-tests branch from 3d4c12a to 8970cec Compare April 19, 2026 20:31
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 8970cec020

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread Tests/SafeDIToolTests/Helpers/SafeDIToolTestExecution.swift
Base automatically changed from dfed--codegen-fixes to main April 19, 2026 21:17
@dfed dfed force-pushed the claude/compile-verify-codegen-tests branch from 8970cec to 5ac9720 Compare April 19, 2026 21:22
dfed added a commit that referenced this pull request Apr 20, 2026
Self-review on #256 flagged that these two tests' opt-out comments
described a cross-module access issue, but the verifier compiles
everything in one synthetic module. The actual failure is Swift's
same-module rule that a `public init`'s signature cannot reference an
`internal` type. Updated comment to match.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: d4d53c0146

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread Tests/SafeDIToolTests/SafeDIToolMockGenerationErrorTests.swift Outdated
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 61f7ec79ad

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines 351 to 352
@Instantiable(generateMock: true, customMockName: "customMock")
public struct Child: Instantiable {
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Align custom mock fixture with asserted call name

This test now declares customMockName: "customMock" and implements customMock(), but the expected generated output still asserts a Child.mock call and compile verification is skipped, so the case can pass even when the generated code references a nonexistent method. In this state the test no longer validates the custom-mock-name path it is intended to cover and can miss regressions in custom mock routing for error scenarios.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

Stale — that test (mock_referencesExpectedMockSignature_whenCustomMockMethodMissingDependencyParameters) was removed from #256 in commit e49f2ad "remove test testing behavior that is unreachable". The macro-rejected Child shape it was pinning can't occur in practice. Current 256 doesn't have this test or any Child.mock assertion in the error-tests file.

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 482a1f32b7

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread Sources/SafeDICore/Generators/ScopeGenerator.swift Outdated
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 305f6bd446

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread Sources/SafeDICore/Generators/ScopeGenerator.swift Outdated
dfed and others added 5 commits April 19, 2026 19:57
Runs `swiftc -typecheck` on test inputs plus generated output to catch
codegen regressions that were previously only exposed by integration
tests. Fixtures that cannot be typechecked in isolation (cross-module
placeholders, platform framework dependencies on Linux, etc.) opt out
via `skipCompileVerification: true` with an in-place comment explaining
the reason.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Self-review on #256 flagged that these two tests' opt-out comments
described a cross-module access issue, but the verifier compiles
everything in one synthetic module. The actual failure is Swift's
same-module rule that a `public init`'s signature cannot reference an
`internal` type. Updated comment to match.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@dfed dfed force-pushed the claude/compile-verify-codegen-tests branch from 305f6bd to e49f2ad Compare April 20, 2026 02:58
dfed and others added 3 commits April 19, 2026 19:58
`generateReturnArgumentList` returns a placeholder comment when neither
the type's initializer nor its mockInitializer can be resolved — a
defensive path for fixtures that slip past the macro's validation.
Add a test that exercises it so the path is covered end-to-end.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…ification

The fixture inherited from #267 had `@Forwarded let callback` on an
`@Instantiable(isRoot: true)` type. The macro rejects that combination
(an isRoot type has no parent to forward from), which the compile
verifier wired up in this PR now catches.

Wrap Root in an App-as-root that instantiates Root via
`Instantiator<Root>` and supplies the forwarded closure at builder-
call time. The test's Child assertion — that `@Received` closure
parameters carry `@escaping` on Child's generated `mock()` — is
unchanged.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
dfed added a commit that referenced this pull request Apr 20, 2026
Codex P1 on #256 (r3107957694): when a back-edge made an
`erasedToConcreteExistential` child unreachable, the generator set
`optionalBuilderPath = nil` while `builderExpression` was assigned a
non-optional default builder. Downstream emission still tried to
`if let safeDIBuilder = \(overridePath)` (constant-wrapper path) or
`\(builderExpression)?(\(argumentList)) ?? …` (leaf path) against that
non-optional value — invalid Swift.

Split the erased path into two cases:

- Override unreachable (`!thisOverrideReachable`): emit a direct
  construction — `\(wrapperType)(\(node.defaultBuilderCall(arguments: arguments)))`
  — with no `if let` / optional-chain dance.
- Override reachable but `optionalBuilderPath` is nil (sendable
  context — extracted local IS optional): keep the existing
  optional-binding behavior.

Fixes the bug for cycles whose pruned edge targets an erased child.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
dfed added a commit that referenced this pull request Apr 20, 2026
Codex P1 on #256 (stale) / re-filed on #259: the closure literal was
marked `@Sendable` only when `typeDescription.propertyType.isSendable`
— i.e. when the node itself was a `SendableInstantiator` wrapper. This
missed cases where a non-Sendable type is reached through a Sendable
ancestor; the closure ends up captured inside an `@Sendable` helper
func and Swift 6 rejects the non-Sendable capture.

Move the decision to the caller, which knows whether the closure is
about to land inside a sendable extraction / `@Sendable func`:
`sendableExtractionPrefix != nil || propertyType.isSendable` now drives
the attribute. The helper takes an `inSendableContext` bool.

Over-annotating is also wrong — a `@Sendable` closure literal in a
non-Sendable slot can fail to typecheck at the assignment site — so we
don't unconditionally emit `@Sendable`.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@dfed dfed merged commit a3395a0 into main Apr 20, 2026
17 checks passed
@dfed dfed deleted the claude/compile-verify-codegen-tests branch April 20, 2026 03:31
dfed added a commit that referenced this pull request Apr 20, 2026
…om Self (#266)

## Summary
- Fix generator to declare `static func mock(...)` with `customMock`'s
return type when `customMock` returns an additional type (e.g. a
protocol fulfilled via `fulfillingAdditionalTypes`) instead of the
concrete type. Previously the method signature returned the concrete
type but its body called `customMock(...)` returning the additional
type, producing a type error.
- Remove `skipCompileVerification: true` from
`mock_extensionUserMockReturningAdditionalTypeUsedForProtocolProperty`
and
`mock_extensionUserMockReturningAdditionalTypeNotUsedForConcreteProperty`,
and add explicit expectations for the extension's own mock file.
- Document the new behavior in the `customMockName` section of
`Documentation/Manual.md`.

## Why

FIXMEs at `SafeDIToolMockGenerationCustomMockTests.swift:1480` and
`:1565` — both the same root cause. With compile verification now
running on every test (#256), these were the last extension-customMock
tests still opting out for a real generator bug.

## Fix detail

`mockMethodReturnType` in `generateMockRootCode` now picks
`mockReturnType.asSource` when the custom mock's declared return type is
NOT compatible with the concrete type (i.e. it's not `Self` / the
concrete type / the property type). In every other case it stays on the
concrete type name, so existing non-protocol-returning customMock tests
are unchanged.

The macro's `mockMethodIncorrectReturnType` check rejects this shape for
concrete (struct) types, so the new code path is only reachable for
extension-based Instantiables.

## Self-review pass
- Pinned the extension's own mock file on the sibling
`NotUsedForConcreteProperty` test so silent drift can't go unnoticed
(`083fc16`).
- Added a Manual.md paragraph under `customMockName` explaining when the
generated `mock()` returns an additional type (`f760b82`).

## Stacked on #256

Base: `claude/compile-verify-codegen-tests`. Three commits on top:
`6a77c78`, `083fc16`, `f760b82`.

## Test plan
- [x] `swift test --traits sourceBuild` — 841 tests pass
- [x] `./CLI/lint.sh`

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
dfed added a commit that referenced this pull request Apr 20, 2026
## Summary
- The verifier ran `swiftc -typecheck` twice per test: once on inputs
alone, then again on inputs + generated output. The first pass existed
purely to disambiguate failure attribution (fixture vs. generated code).
- Swap the ordering: run the combined pass first, and re-run the
inputs-alone pass only as a diagnostic fallback when the combined pass
fails. Green-path tests pay one subprocess instead of two.

## Why
Compile verification (added in #256) roughly doubled test-suite wall
time. Most of that cost is the per-test `swiftc` startup — forking,
loading the compiler, loading the `SafeDIMacros` compiler plugin,
typechecking under Swift 6 strict-Sendable. The input-only preemptive
pass is paid on every test even though attribution only matters when
something is broken.

## Measurements
Local `time swift test --traits sourceBuild` on the same 842-test suite:
- Before: **19.49s**
- After: **11.71s** (~40% wall-time reduction)

## Diagnostic behavior unchanged
Failure messages still read "Test inputs failed to compile on their own"
vs. "Generated code failed to compile alongside test inputs" depending
on whether the fallback input-only run also fails. Attribution only pays
the extra subprocess when something is already broken.

## Test plan
- [x] `swift test --traits sourceBuild` — 842 tests pass
- [x] `./CLI/lint.sh`

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
dfed added a commit that referenced this pull request Apr 20, 2026
…arc set (#259)

## Problem

Multi-hop lazy-instantiation cycles (e.g. `A → Instantiator<B> → B →
Instantiator<C> → C → Instantiator<A>`) produced
`SafeDIMockConfiguration` structs that referenced themselves through the
cycle — Swift rejects those as infinite-size value types, so the
generated mock code failed to compile.

The root cause: the old generator relied on a per-tree `isPropertyCycle`
flag that breaks at whichever edge the walker happened to cross last.
Different roots walking the same cycle produced different shapes for the
same shared config struct.

## Fix

Compute cycle back-edges **once**, globally, in
`DependencyTreeGenerator.computeCycleEdges` via an alphabetical-DFS
feedback arc set. Thread the chosen `cycleEdges` through both:
- `SafeDIMockConfiguration` struct generation (so every root emits the
same shape for a given type), and
- override-path navigation inside the generated `mock()` bodies (so call
sites agree on which slot is pruned).

With the back-edge chosen globally, every root sees the same cycle break
and the shared struct stops recursing into itself.

## Secondary fixes required to make the above compile

- **Callee-scope preservation for pruned defaults.** When
`resolveBuilderArguments` prunes a back-edge, it used to inline raw
default-expression text at the caller. It now emits a closure form (`{
Type(label: $0) }`, or `{ @sendable in … }` in sendable contexts) that
captures only deps + required non-deps, so Swift's default-argument
thunk fires in the callee's lexical scope — preserving `Self.*`, private
members, and file-scoped helpers.
- **`ErasedInstantiator` pruned-back-edge branch.**
`generateInstantiatorBinding`'s erased arm emitted `if let
\(builderExpression)` even when `builderExpression` was a non-optional
default. Split the arm so pruned back-edges emit direct construction.
- **Narrowed `@Sendable` on config-struct closure fields.** Only marks
`@Sendable` on the specific override slot reached through a
`SendableInstantiator` / `SendableErasedInstantiator`, not on the whole
enclosing struct.

## Tests

Compile verification (from #256) typechecks every fixture's generated
code. New regressions:

- `mock_generatedForFullyLazyInstantiationCycle` — 3-node A↔B↔C↔A, now
with compile verification enabled (previously skipped).
- `mock_generatedForFourNodeFullyLazyInstantiationCycle` — A→B→C→D→A,
SCC handling scales past 3 nodes.
- `mock_generatedForCycleWithNonCycleSibling` — A↔B plus A→C, pruning
operates per-edge not per-node.
- `mock_generatedForLazyCycleBeneathConstantChild` — cycle descendant
under the constant-wrapper recursion path.
- `mock_generatedForErasedInstantiatorBackEdgeInLazyCycle` —
`ErasedInstantiator` property as the selected back-edge.
- `mock_generatedForCycleWithDefaultValuedNonDependencyParameter` —
labeled non-dep default on a cycle node.
- `mock_generatedForCycleWithCustomMockAndLabeledDefaultOnCycleNode` —
customMock + labeled default combined.
- `mock_generatedForRootSelfInstantiatorCycle` — self-cycle root, pins
that the config struct is still emitted.

Also fixes the `AnyService` fixture in
`mock_usesMockOnly_whenProductionHasNoMockAndBothFulfillSameAdditionalType`
(was a concrete class two structs claimed to fulfill — switched to a
protocol).

## Test plan
- [x] `swift test --traits sourceBuild` — 850 tests pass
- [x] `./CLI/lint.sh`
- [x] Codecov 100%

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
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.

1 participant