mirror of
https://github.com/leanprover/lean4.git
synced 2026-03-17 18:34:06 +00:00
fix: set implicitReducible on grandparent subobject projections (#12701)
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 <noreply@anthropic.com>
This commit is contained in:
@@ -1549,6 +1549,16 @@ def elabStructureCommand : InductiveElabDescr where
|
||||
if fieldInfo.kind.isInCtor then
|
||||
enableRealizationsForConst fieldInfo.declName
|
||||
if view.isClass then
|
||||
-- Set implicitReducible on subobject projections to class parents.
|
||||
-- mkProjections defers reducibility to addParentInstances, but
|
||||
-- addParentInstances only handles direct parents. Subobject fields
|
||||
-- for non-direct parents (grandparents promoted to constructor
|
||||
-- subobjects during diamond flattening) also need implicitReducible
|
||||
-- to be unfoldable at .instances transparency.
|
||||
for fieldInfo in fieldInfos do
|
||||
if let .subobject parentName := fieldInfo.kind then
|
||||
if isClass (← getEnv) parentName then
|
||||
setReducibilityStatus fieldInfo.declName .implicitReducible
|
||||
addParentInstances parentInfos
|
||||
-- Add field docstrings here (after @[class] attribute is applied)
|
||||
-- so that Verso docstrings can use the class.
|
||||
|
||||
43
tests/elab/grandparentImplicitReducible.lean
Normal file
43
tests/elab/grandparentImplicitReducible.lean
Normal file
@@ -0,0 +1,43 @@
|
||||
import Lean
|
||||
|
||||
/-!
|
||||
# Grandparent subobject projections should be `@[implicit_reducible]`
|
||||
|
||||
When `class C extends P₁, P₂` has diamond inheritance, some ancestor structures
|
||||
end up as constructor subobject fields even though they aren't direct parents.
|
||||
These grandparent projections need `@[implicit_reducible]` so they unfold at
|
||||
`.instances` transparency.
|
||||
|
||||
For example, with `MyMonoid extends MySemigroup, MyMulOneClass` where both share
|
||||
`MyMul`, the structure `MyOne` becomes a constructor subobject of `MyMonoid`
|
||||
(it has no overlap with `MySemigroup`). So `MyMonoid.toMyOne` is created by
|
||||
`mkProjections` as a subobject projection, but it is NOT a direct parent —
|
||||
it's a grandparent reached through `MyMulOneClass`.
|
||||
|
||||
Previously, `addParentInstances` only set `@[implicit_reducible]` on direct
|
||||
parent projections. This test verifies that grandparent subobject projections
|
||||
also receive `@[implicit_reducible]`.
|
||||
-/
|
||||
|
||||
-- Minimal hierarchy with a diamond via MyMul
|
||||
class MyOne (α : Type _) where one : α
|
||||
class MyMul (α : Type _) where mul : α → α → α
|
||||
class MyMulOneClass (M : Type _) extends MyOne M, MyMul M
|
||||
class MySemigroup (G : Type _) extends MyMul G
|
||||
class MyMonoid (M : Type _) extends MySemigroup M, MyMulOneClass M
|
||||
|
||||
open Lean in
|
||||
def showReducibility (n : Name) : CoreM Unit := do
|
||||
IO.println s!"{n}: {repr (← getReducibilityStatus n)}"
|
||||
|
||||
/--
|
||||
info: MyMonoid.toMySemigroup: Lean.ReducibilityStatus.implicitReducible
|
||||
MyMonoid.toMyMulOneClass: Lean.ReducibilityStatus.implicitReducible
|
||||
MyMonoid.toMyOne: Lean.ReducibilityStatus.implicitReducible
|
||||
-/
|
||||
#guard_msgs in
|
||||
#eval do
|
||||
showReducibility ``MyMonoid.toMySemigroup
|
||||
showReducibility ``MyMonoid.toMyMulOneClass
|
||||
-- Grandparent subobject projection should also be implicitReducible
|
||||
showReducibility ``MyMonoid.toMyOne
|
||||
Reference in New Issue
Block a user