Skip to content

fix: qualify Option in nested scopes to prevent prelude shadowing (#36)#39

Merged
iainmcgin merged 3 commits intoanthropics:mainfrom
th0114nd:fix/option-prelude-shadow
Apr 23, 2026
Merged

fix: qualify Option in nested scopes to prevent prelude shadowing (#36)#39
iainmcgin merged 3 commits intoanthropics:mainfrom
th0114nd:fix/option-prelude-shadow

Conversation

@th0114nd
Copy link
Copy Markdown
Contributor

@th0114nd th0114nd commented Apr 5, 2026

Summary

Fixes #36 — a proto message named Option shadows core::option::Option, causing type errors on oneof fields in nested scopes.

  • Extended ImportResolver with child_for_message() to propagate blocked prelude names through the use super::* module chain
  • Each recursive generate_message call now receives a child resolver that accounts for sibling types in its module scope
  • Qualified bare Option in custom deserialize temporaries and skip_serializing_if predicates
  • Added tests for nested and top-level Option message scenarios

Test plan

  • cargo test -p buffa-codegen (239 tests pass)
  • cargo test --workspace (all pass)
  • cargo clippy --workspace --all-targets (clean)
  • No WKT/bootstrap regen needed (no output changes for non-shadowed cases)

Made with Cursor

@th0114nd th0114nd force-pushed the fix/option-prelude-shadow branch from 3dc06f5 to a19bc77 Compare April 17, 2026 21:14
@th0114nd th0114nd marked this pull request as ready for review April 17, 2026 21:14
@th0114nd th0114nd marked this pull request as draft April 17, 2026 21:17
@th0114nd th0114nd force-pushed the fix/option-prelude-shadow branch from a19bc77 to 71bc6ea Compare April 17, 2026 21:24
@th0114nd th0114nd marked this pull request as ready for review April 17, 2026 21:25
@th0114nd
Copy link
Copy Markdown
Contributor Author

th0114nd and others added 3 commits April 23, 2026 16:53
…thropics#36)

When a proto message named `Option` is nested inside another message,
the generated `pub struct Option` shadows `core::option::Option` in
the parent module scope. This caused struct fields like
`pub value: Option<option::Value>` to resolve to the proto struct
(0 generic args) instead of the standard library type.

Fix: extend ImportResolver with `child_for_message()` to propagate
blocked prelude names through the `use super::*` module chain.
Each recursive `generate_message` call now receives a child resolver
that accounts for sibling types in its module scope. Also qualify
bare `Option` in custom deserialize temporaries and
`skip_serializing_if` predicates.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Made-with: Cursor
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
The unit tests in tests/naming.rs only checked codegen output substrings.
This adds:

- buffa-test/protos/prelude_shadow.proto built with views + JSON, covering
  the gh#36 nested case, a sibling-propagation case (Outer.Option +
  Outer.Middle.Inner where Inner must qualify Option via two `use super::*`
  hops), and the top-level case under JSON. Compilation is the assertion.
- Two runtime tests in tests/collision.rs that round-trip the generated
  types over binary and JSON.
- A unit test in tests/naming.rs for the sibling-propagation case,
  verifying child_for_message inherits the parent blocked set.

Audited all codegen modules: view.rs, enumeration.rs, impl_message.rs,
extension.rs, impl_text.rs already emit ::core::option::Option uniformly,
and Result/Default/Debug are universally ::core::-qualified, so no
additional qualification sites were needed.

Co-authored-by: Iain McGinniss <309153+iainmcgin@users.noreply.github.com>
@iainmcgin iainmcgin force-pushed the fix/option-prelude-shadow branch from 42122b0 to 6964025 Compare April 23, 2026 16:58
Copy link
Copy Markdown
Collaborator

@iainmcgin iainmcgin left a comment

Choose a reason for hiding this comment

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

[claude code] Audited all Option<...> emission sites across the codegen crate — view.rs/enumeration.rs/impl_message.rs/extension.rs/impl_text.rs already use fully-qualified ::core::option::Option, so the resolver threading in message.rs is sufficient. Result/Default/Debug are universally ::core::-qualified already, so PRELUDE_NAMES = ["Option"] is correct.

Added an end-to-end regression proto (buffa-test/protos/prelude_shadow.proto, built with views + JSON) covering top-level, nested (gh#36 reproducer), and sibling-propagation (Outer.Option + Outer.Middle.Inner) cases, plus a unit test verifying child_for_message inherits the parent blocked set. Rebased onto current main.

LGTM, thanks for the fix.

@iainmcgin iainmcgin enabled auto-merge (squash) April 23, 2026 16:59
@iainmcgin iainmcgin merged commit f5690d7 into anthropics:main Apr 23, 2026
7 checks passed
@github-actions github-actions Bot locked and limited conversation to collaborators Apr 23, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Proto message named Option shadows core::option::Option, causing type errors on oneof fields

2 participants