fix: Sym.DSimp.zetaDelta should unfold let-bound variables in head position - #15362
Merged
Merged
Conversation
…position This PR fixes `Sym.DSimp.zetaDelta` and `Sym.DSimp.zetaDeltaAll` so that they unfold a let-bound variable that appears as the head of an application. Previously, `dsimp [foo]` and `dsimp [*]` in `grind`/`sym`, and the `bv_decide` normalization passes, left terms such as `foo a b` untouched when `foo := fun x y => x + y` was a local definition, while `Meta.DSimp` reduces them to `a + b`. The root cause is that `Sym.dsimp` intentionally does not visit the head of an application (`dsimpAppArgs` only traverses the arguments), and both simprocs only matched a bare `.fvar`. As a result, a let-bound `.fvar` in argument position was unfolded, but the same `.fvar` in head position was never seen by the simproc. The fix makes `zetaDelta` and `zetaDeltaAll` match on `e.getAppFn`. When the head is a let-bound `.fvar`, the result is its value applied to the original arguments, built with `mkAppNS` to preserve maximal sharing. Beta-reduction of the exposed lambda is still left to the `beta` simproc, so `zetaDeltaAll >> beta` yields `a + b = b + a` for the example above. The doc-string of `dsimpAppArgs` now states the resulting contract: `pre`/`post` simprocs that rewrite heads must match on the whole application. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
leodemoura
enabled auto-merge
September 27, 2026 17:15
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This PR fixes
Sym.DSimp.zetaDeltaandSym.DSimp.zetaDeltaAllso that they unfold a let-bound variable that appears as the head of an application. Previously,dsimp [foo]anddsimp [*]ingrind/sym, and thebv_decidenormalization passes, left terms such asfoo a buntouched whenfoo := fun x y => x + ywas a local definition, whileMeta.DSimpreduces them toa + b.The root cause is that
Sym.dsimpintentionally does not visit the head of an application (dsimpAppArgsonly traverses the arguments), and both simprocs only matched a bare.fvar. As a result, a let-bound.fvarin argument position was unfolded, but the same.fvarin head position was never seen by the simproc. The fix makeszetaDeltaandzetaDeltaAllmatch one.getAppFn. When the head is a let-bound.fvar, the result is its value applied to the original arguments, built withmkAppNSto preserve maximal sharing. Beta-reduction of the exposed lambda is still left to thebetasimproc, sozetaDeltaAll >> betayieldsa + b = b + afor the example above. The doc-string ofdsimpAppArgsnow states the resulting contract:pre/postsimprocs that rewrite heads must match on the whole application.🤖 Generated with Claude Code