Skip to content

fix: set implicitReducible on grandparent subobject projections#12701

Merged
kim-em merged 3 commits intoleanprover:masterfrom
kim-em:kim/grandparent-implicit-reducible
Mar 1, 2026
Merged

fix: set implicitReducible on grandparent subobject projections#12701
kim-em merged 3 commits intoleanprover:masterfrom
kim-em:kim/grandparent-implicit-reducible

Conversation

@kim-em
Copy link
Copy Markdown
Collaborator

@kim-em kim-em commented Feb 26, 2026

This PR fixes a gap in how @[implicit_reducible] is assigned to parent projections during structure elaboration.

When class C extends P₁, P₂ has diamond inheritance, some ancestor structures become constructor subobject fields even though they aren't direct parents. For example, in Monoid extends Semigroup, MulOneClass, One becomes a constructor subobject of Monoid — its field one doesn't overlap with Semigroup's fields, and inSubobject? is none during MulOneClass flattening.

mkProjections creates the projection Monoid.toOne but defers reducibility to addParentInstances (guarded by if !instImplicit). However, addParentInstances only processes direct parents from the extends clause. Grandparent subobject projections fall through the gap and stay semireducible.

This causes defeq failures when backward.isDefEq.respectTransparency is enabled (#12179): at .instances transparency, the semireducible grandparent projection can't unfold, so two paths to the same ancestor structure aren't recognized as definitionally equal.

Fix: before addParentInstances, iterate over all .subobject fields and set implicitReducible on those whose parent is a class.

🤖 Prepared with Claude Code

When a class `C extends P₁, P₂` has diamond inheritance, some ancestor
structures become constructor subobject fields even though they aren't
direct parents. For example, in `Monoid extends Semigroup, MulOneClass`,
`One` becomes a constructor subobject because its field (`one`) doesn't
overlap with `Semigroup`'s fields and `inSubobject?` is `none` during
`MulOneClass` flattening.

`mkProjections` creates the projection (e.g., `Monoid.toOne`) but defers
reducibility to `addParentInstances`. However, `addParentInstances` only
processes direct parents from the `extends` clause. Grandparent subobject
projections fall through the gap — they're never registered as instances
and never get `implicitReducible`.

This causes defeq failures when `backward.isDefEq.respectTransparency` is
enabled: at `.instances` transparency, the semireducible grandparent
projection can't unfold, so two paths to the same ancestor structure
aren't recognized as definitionally equal.

Fix: before `addParentInstances`, iterate over all `.subobject` fields
and set `implicitReducible` on those whose parent is a class. This is
idempotent with `addParentInstances` for direct parents and fills the
gap for grandparent subobjects.

Co-Authored-By: Claude Opus 4.6 <[email protected]>
@github-actions github-actions bot added the toolchain-available A toolchain is available for this PR, at leanprover/lean4-pr-releases:pr-release-NNNN label Feb 26, 2026
@mathlib-lean-pr-testing
Copy link
Copy Markdown

Mathlib CI status (docs):

  • ❗ Batteries/Mathlib CI will not be attempted unless your PR branches off the nightly-with-mathlib branch. Try git rebase 65a0c618068bd01a933596cdb6dd3b9b482d24a8 --onto c595413fccaa47ebdc399d9b817c17425687fc26. You can force Mathlib CI using the force-mathlib-ci label. (2026-02-26 10:37:34)

@leanprover-bot
Copy link
Copy Markdown
Collaborator

Reference manual CI status:

  • ❗ Reference manual CI will not be attempted unless your PR branches off the nightly-with-manual branch. Try git rebase 65a0c618068bd01a933596cdb6dd3b9b482d24a8 --onto 8038a8b8904f89ad9542c8eda11379f8f006eab1. You can force reference manual CI using the force-manual-ci label. (2026-02-26 10:37:37)

The #guard_msgs + #print approach failed because #print includes the
definition body, which is hard to predict exactly. Use #eval with
getReducibilityStatus instead.

Co-Authored-By: Claude Opus 4.6 <[email protected]>
@kim-em kim-em added the changelog-language Language features and metaprograms label Feb 26, 2026
Move `import Lean` before module doc, use `#guard_msgs` with
`getReducibilityStatus` + `repr` to check reducibility programmatically.
The previous test used `guard` (no `Alternative` for `CommandElabM`)
and the wrong `getReducibilityStatus` signature.

Co-Authored-By: Claude Opus 4.6 <[email protected]>
@mathlib-lean-pr-testing
Copy link
Copy Markdown

Mathlib CI status (docs):

@mathlib-lean-pr-testing mathlib-lean-pr-testing bot added the breaks-mathlib This is not necessarily a blocker for merging: but there needs to be a plan label Feb 26, 2026
@mathlib-lean-pr-testing
Copy link
Copy Markdown

Mathlib CI status (docs):

@mathlib-lean-pr-testing
Copy link
Copy Markdown

Mathlib CI status (docs):

@kim-em kim-em added this pull request to the merge queue Mar 1, 2026
Merged via the queue into leanprover:master with commit 3ea59e1 Mar 1, 2026
29 checks passed
@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Mar 1, 2026

The backport to releases/v4.29.0 failed:

The process '/usr/bin/git' failed with exit code 1

To backport manually, run these commands in your terminal:

# Fetch latest updates from GitHub
git fetch
# Create a new working tree
git worktree add .worktrees/backport-releases/v4.29.0 releases/v4.29.0
# Navigate to the new working tree
cd .worktrees/backport-releases/v4.29.0
# Create a new branch
git switch --create backport-12701-to-releases/v4.29.0
# Cherry-pick the merged commit of this pull request and resolve the conflicts
git cherry-pick -x --mainline 1 3ea59e15b8ebd9b0b6fc2ccc9bf64eaeb0ba6499
# Push it to GitHub
git push --set-upstream origin backport-12701-to-releases/v4.29.0
# Go back to the original working tree
cd ../..
# Delete the working tree
git worktree remove .worktrees/backport-releases/v4.29.0

Then, create a pull request where the base branch is releases/v4.29.0 and the compare/head branch is backport-12701-to-releases/v4.29.0.

kim-em added a commit that referenced this pull request Mar 1, 2026
This PR fixes a gap in how `@[implicit_reducible]` is assigned to parent
projections during structure elaboration.

When `class C extends P₁, P₂` has diamond inheritance, some ancestor
structures become constructor subobject fields even though they aren't
direct parents. For example, in `Monoid extends Semigroup, MulOneClass`,
`One` becomes a constructor subobject of `Monoid` — its field `one`
doesn't overlap with `Semigroup`'s fields, and `inSubobject?` is `none`
during `MulOneClass` flattening.

`mkProjections` creates the projection `Monoid.toOne` but defers
reducibility to `addParentInstances` (guarded by `if !instImplicit`).
However, `addParentInstances` only processes direct parents from the
`extends` clause. Grandparent subobject projections fall through the gap
and stay `semireducible`.

This causes defeq failures when `backward.isDefEq.respectTransparency`
is enabled (#12179): at `.instances` transparency, the semireducible
grandparent projection can't unfold, so two paths to the same ancestor
structure aren't recognized as definitionally equal.

Fix: before `addParentInstances`, iterate over all `.subobject` fields
and set `implicitReducible` on those whose parent is a class.

🤖 Prepared with Claude Code

---------

Co-authored-by: Claude Opus 4.6 <[email protected]>
github-merge-queue bot pushed a commit that referenced this pull request Mar 3, 2026
…ns (#12778)

This PR fixes an inconsistency in `getStuckMVar?` where the instance
argument to class projection functions and auxiliary parent projections
was not whnf-normalized before checking for stuck metavariables. Every
other case in `getStuckMVar?` (recursors, quotient recursors, `.proj`
nodes) normalizes the major argument via `whnf` before recursing — class
projection functions and aux parent projections were the exception.

This bug was identified by Matthew Jasper. When the instance parameter
to a class projection is not normalized, `getStuckMVar?` may fail to
detect stuck metavariables that would be revealed by whnf, or conversely
may report stuckness for expressions that would reduce to constructors.
This caused issues with `OfNat` and `Zero` at
`with_reducible_and_instances` transparency.

Note: PR #12701 (already merged) is also required to fix the original
Mathlib examples.
kim-em pushed a commit that referenced this pull request Mar 4, 2026
…ns (#12778)

This PR fixes an inconsistency in `getStuckMVar?` where the instance
argument to class projection functions and auxiliary parent projections
was not whnf-normalized before checking for stuck metavariables. Every
other case in `getStuckMVar?` (recursors, quotient recursors, `.proj`
nodes) normalizes the major argument via `whnf` before recursing — class
projection functions and aux parent projections were the exception.

This bug was identified by Matthew Jasper. When the instance parameter
to a class projection is not normalized, `getStuckMVar?` may fail to
detect stuck metavariables that would be revealed by whnf, or conversely
may report stuckness for expressions that would reduce to constructors.
This caused issues with `OfNat` and `Zero` at
`with_reducible_and_instances` transparency.

Note: PR #12701 (already merged) is also required to fix the original
Mathlib examples.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

backport releases/v4.29.0 breaks-mathlib This is not necessarily a blocker for merging: but there needs to be a plan changelog-language Language features and metaprograms toolchain-available A toolchain is available for this PR, at leanprover/lean4-pr-releases:pr-release-NNNN

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants