Skip to content

Give enums nested in a body, impl, or closure a unique SMT-safe datatype name - #317

Open
coord-e wants to merge 2 commits into
mainfrom
claude/gifted-bohr-52o26a
Open

coord-e wants to merge 2 commits into
mainfrom
claude/gifted-bohr-52o26a

Conversation

@coord-e

@coord-e coord-e commented Oct 2, 2026

Copy link
Copy Markdown
Owner

Fixes #316.

Problem

refine::datatype_symbol named an enum's datatype after tcx.def_path_str(did). If the enum is declared inside a function body, that path:

  • is not a valid SMT-LIB symbol when the function is a trait impl method (<S as T>::f::E) or a closure (main::{closure#0}::E), so the solver rejects the file (unknown sort 'A1_<S');
  • is not unique when two blocks of one function each declare an enum E (both become f.E), so the analyzer panics at src/refine/env.rs:444.

Change

If every segment of an item's def path is DefPathData::TypeNs (modules and types), the item keeps its readable def_path_str name. That name is unique and SMT-safe. Any other item gets the existing stable_def_id_symbol ({name}_{DefPathHash}), which user-defined predicates already use.

At first I used stable_def_id_symbol for every enum. That produced semantically identical SMT, but std.option.Option became Option_<hash>, and with that one name PCSat took more than 30s on tests/ui/pass/slice_split_first_mut_loop.rs instead of about 5s. PCSat's running time depends on symbol names. Keeping module-level names unchanged means every existing test produces byte-identical SMT. I confirmed this with THRUST_OUTPUT_DIR for that test.

Tests

tests/ui/{pass,fail}/enum_local_in_trait_impl.rs: two impls of one trait, each declaring its own local enum E with different variants. Before this change, the pass file fails with a solver parse error.

cargo test locally, with z3 5.0.0 and the pinned PCSat: 387/388 pass. The one failure is tests/ui/fail/slice_split_first_mut_loop.rs, and it is flaky without this change too. Rerunning it alone on the same input gave Timeout(30s) once and then Unsat in 18s and 11s. This PR doesn't change the SMT for that test. cargo clippy -- -D warnings is clean. I didn't run rustfmt because it isn't installed in this container; the diff is small and formatted by hand.

🤖 Generated with Claude Code

https://claude.ai/code/session_01NuD8BuMA1PzziM9f59oQHb


Generated by Claude Code

…ype name

The datatype symbol of an enum was its `def_path_str`. For an enum declared
inside a trait impl method or a closure, that path contains spaces, braces,
and `#` (`<S as T>::f::E`, `main::{closure#0}::E`), so the emitted SMT-LIB was
rejected by the solver. Two same-named enums in different blocks of one
function also shared a symbol and crashed the analyzer.

Items whose def path is entirely in the type namespace (modules and types)
keep their readable path name, which is unique and SMT-safe; any other item
uses the existing `stable_def_id_symbol`. Keeping the old names for module
items also keeps the generated SMT for existing programs unchanged, which
matters because PCSat's running time is sensitive to symbol names.

Fixes #316

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NuD8BuMA1PzziM9f59oQHb
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 2, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-03T02:27:36.525200Z ff61c0b New commits
ℹ️ 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" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NuD8BuMA1PzziM9f59oQHb

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: ff61c0b53c

ℹ️ 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 src/refine.rs

pub fn datatype_symbol(tcx: mir_ty::TyCtxt<'_>, did: DefId) -> DatatypeSymbol {
DatatypeSymbol::new(tcx.def_path_str(did).replace("::", "."))
DatatypeSymbol::new(stable_def_id_symbol(tcx, did))

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Preserve names for module-level datatypes

When verification uses an existing module-level enum—most notably std.option.Option in tests/ui/pass/slice_split_first_mut_loop.rs—this unconditionally replaces its prior readable symbol with a hash-suffixed name even though only locally nested enums need disambiguation. PCSat is sensitive to these names: this renaming increases that representative case from roughly 5 seconds to beyond the solver's 30-second default, turning a valid program into a timeout. Keep the old def_path_str symbol for paths consisting only of module/type-namespace segments and use the stable def-id symbol only for nested items.

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.

Leaving this as is. The maintainer asked to drop the module-path branch, so this PR now uses the stable symbol for every enum. The slowdown is PCSat reacting to one particular name string: the SMT is semantically identical, and other renamings of the same file solve in 6–9s. So it isn't a good reason to keep two naming schemes. I'm waiting for CI on ff61c0b to see whether that test times out on the runner.


Generated by Claude Code

@coord-e

coord-e commented Oct 3, 2026

Copy link
Copy Markdown
Owner Author

CI test on ff61c0b fails: tests/ui/pass/slice_split_first_mut_loop.rs → verification error: Timeout(30s) (391 other tests pass).

This is caused by this PR's renaming. The SMT is identical to main except that std.option.Option becomes Option_dc33fea427b8ae3cee3022bbf94c4dcc. With that name PCSat doesn't finish even with THRUST_SOLVER_TIMEOUT_SECS=300 (two local runs), so raising this test's timeout, as was done for other tests before, won't help. Main solves the same file in about 5s. Replacing the hash by hand with another string of the same shape (Option_0123456789abcdef0123456789abcdef, Option_x, core.option.Option) solves in 6–9s. So PCSat diverges on this one string.

Ways forward, waiting on a decision:

  1. Go back to a1b0e58: keep the readable path for module items and use the stable symbol only for nested ones. CI was green there.
  2. Keep the uniform stable symbol and deal with the PCSat sensitivity separately; this PR stays red until then.

Generated by Claude Code

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

2 participants