`euf_seq_plugin` was applying several regex concat simplifications
against raw child enodes instead of canonical e-graph roots, so rules
could silently miss after merges. It also merged loop bounds with
unchecked unsigned addition, allowing overflowed bounds.
- **Root-canonical checks in simplification rules**
- Use `get_root()` for nullable/full-seq absorption checks.
- Update `same_star_body` to test `is_star` on roots and compare rooted
star bodies.
- Evaluate extended star rules (`v*.v*.c` / `c.v*.v*`) against concat
roots, not syntactic children.
- **Safe loop merge arithmetic**
- Gate loop merging on overflow-safe bound addition checks before
constructing merged `re.loop`.
- **Re-simplify concats affected by child merges**
- In `propagate_merge`, re-run `propagate_simplify` for tracked concat
nodes whose left/right child root is in the merged class, not only
concats in the class itself.
- **Regression coverage in `src/test/euf_seq_plugin.cpp`**
- Added focused tests for:
- star merge firing after child-to-star merge,
- extended star rule using root concat shape,
- nullable absorption via merged roots,
- loop-merge non-application on overflow.
```cpp
// before: structural check on non-canonical enode
if (is_concat(b, b1, b2) && same_star_body(a, b1))
// after: structural check on canonical representative
if (is_concat(b->get_root(), b1, b2) && same_star_body(a, b1))
```
---------
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Address remaining review feedback from PR #8820:
- Use pointer comparison instead of ID comparison in enode_concat_eq
- Remove redundant num_args() == 2 check from is_str_concat/is_re_concat
- Update euf_sgraph.h abstract to detail seq_plugin features
Co-authored-by: NikolajBjorner <3085284+NikolajBjorner@users.noreply.github.com>