lean4-htt/tests/lean/run/structBinderUpdates.lean
Kyle Miller 6cf22b32aa
feat: custom structure constructors can update binder kinds of parameters (#9480)
This PR adds a feature where `structure` constructors can override the
inferred binder kinds of the type's parameters. In the following, the
`(p)` binder on `toLp` causes `p` to be an explicit parameter to
`WithLp.toLp`:
```lean
structure WithLp (p : Nat) (V : Type) where toLp (p) ::
  ofLp : V
```
This reflects the syntax of the feature added in #7742 for overriding
binder kinds of structure projections. Similarly, only those parameters
in the header of the `structure` may be updated; it is an error to try
to update binder kinds of parameters included via `variable`.

Closes #9072.

Fixes a possible bug from stale caches when creating the type of the
constructor.
2025-07-23 16:33:34 +00:00

201 lines
5.3 KiB
Text
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/-!
# Tests of structure parameter binder updates
-/
/-!
Motivating issue: https://github.com/leanprover/lean4/issues/3574
Normally one defines a `cast_eq_zero_iff'` field and restates a `cast_eq_zero_iff` version.
-/
namespace Issue3574
class AddMonoidWithOne (R : Type u) extends Add R, Zero R where
natCast : Nat → R
instance [AddMonoidWithOne R] : Coe Nat R where
coe := AddMonoidWithOne.natCast
attribute [coe] AddMonoidWithOne.natCast
class CharP [AddMonoidWithOne R] (p : Nat) : Prop where
cast_eq_zero_iff (R) (p) : ∀ x : Nat, (x : R) = 0 ↔ p x
-- Both `R` and `p` are explicit now.
/--
info: Issue3574.CharP.cast_eq_zero_iff.{u_1} (R : Type u_1) {inst✝ : AddMonoidWithOne R} (p : Nat) [self : CharP p]
(x : Nat) : ↑x = 0 ↔ p x
-/
#guard_msgs in #check CharP.cast_eq_zero_iff
-- Multiple parameters can be updated at once.
class CharP' [AddMonoidWithOne R] (p : Nat) : Prop where
cast_eq_zero_iff (R p) : ∀ x : Nat, (x : R) = 0 ↔ p x
/--
info: Issue3574.CharP'.cast_eq_zero_iff.{u_1} (R : Type u_1) {inst✝ : AddMonoidWithOne R} (p : Nat) [self : CharP' p]
(x : Nat) : ↑x = 0 ↔ p x
-/
#guard_msgs in #check CharP'.cast_eq_zero_iff
end Issue3574
/-!
Basic test for structures.
-/
namespace Ex1
structure Inhabited (α : Type) where
default : α
/-- info: Ex1.Inhabited.default {α : Type} (self : Inhabited α) : α -/
#guard_msgs in #check Inhabited.default
structure Inhabited' (α : Type) where
default (α) : α
/-- info: Ex1.Inhabited'.default (α : Type) (self : Inhabited' α) : α -/
#guard_msgs in #check Inhabited'.default
end Ex1
/-!
Basic test for classes.
-/
namespace Ex2
class Inhabited (α : Type) where
default : α
/-- info: Ex2.Inhabited.default {α : Type} [self : Inhabited α] : α -/
#guard_msgs in #check Inhabited.default
class Inhabited' (α : Type) where
default (α) : α
/-- info: Ex2.Inhabited'.default (α : Type) [self : Inhabited' α] : α -/
#guard_msgs in #check Inhabited'.default
end Ex2
/-!
Example with a parameter from a `variable`
-/
namespace Ex3
class Inhabited (α : Type) where
default : α
/-- info: Ex3.Inhabited.default {α : Type} [self : Inhabited α] : α -/
#guard_msgs in #check Inhabited.default
class Inhabited' (α : Type) where
default (α) : α
/-- info: Ex3.Inhabited'.default (α : Type) [self : Inhabited' α] : α -/
#guard_msgs in #check Inhabited'.default
end Ex3
/-!
Trying to set a `variable` binder kind; only parameters in the declaration itself can be overridden.
Rationale: we found in mathlib that often users had large binder lists declared at the beginning of files,
and the structure fields accidentally were shadowing them.
-/
namespace Ex4
variable (α : Type)
/--
error: only parameters appearing in the declaration header may have their binders kinds be overridden
If this is not intended to be an override, use a binder with a type, for example '(x : _)'.
-/
#guard_msgs in
class Inhabited where
default (α) : α
end Ex4
/-!
Here, `(α β)` is not an override since `β` is not an existing parameter, so `α` is treated as a binder.
-/
namespace Ex5
/-- error: Failed to infer type of binder `α` -/
#guard_msgs in
class C (α : Type) where
f (α β) : β
end Ex5
/-!
Here, `(α β)` is not an override since `β` is a field.
-/
namespace Ex6
/-- error: Failed to infer type of binder `α` -/
#guard_msgs in
class C (α : Type) where
β : Type
f (α β) : β
end Ex6
/-!
## Constructor updates
-/
/-!
Comparing natural constructor binder kinds to the updated ones.
-/
namespace ExC1
structure WithLp (p : Nat) (V : Type) where toLp ::
ofLp : V
/-- info: constructor ExC1.WithLp.toLp : {p : Nat} → {V : Type} → V → WithLp p V -/
#guard_msgs in #print WithLp.toLp
structure WithLp' (p : Nat) (V : Type) where toLp (p) ::
ofLp : V
/-- info: constructor ExC1.WithLp'.toLp : (p : Nat) → {V : Type} → V → WithLp' p V -/
#guard_msgs in #print WithLp'.toLp
end ExC1
/-!
Checking errors
-/
namespace ExC2
/-- error: Expecting binders that update binder kinds of type parameters. -/
#guard_msgs in
structure WithLp (p : Nat) (V : Type) where toLp (p : _) ::
ofLp : V
variable (n : Nat)
/--
error: only parameters appearing in the declaration header may have their binders kinds be overridden
If this is not intended to be an override, use a binder with a type, for example '(x : _)'.
-/
#guard_msgs in
structure WithLp (p : Nat) (V : Type) where toLp (n) ::
ofLp : V
/-!
Even if `n` is used by `ofLp`, the restriction is still in place.
Motivation 1: the fields themselves have the same restriction, so it's for consistency.
Motivation 2: we should be able to tell whether the param binder update is legit without looking at all the fields.
Motivation 3: the constructor type is constructed before we know which `variable`s will be included. That would take participation of MutualInductive.
-/
/--
error: only parameters appearing in the declaration header may have their binders kinds be overridden
If this is not intended to be an override, use a binder with a type, for example '(x : _)'.
-/
#guard_msgs in
structure WithLp (p : Nat) (V : Type) where toLp (n) ::
ofLp : Fin n → V
/-- error: Expecting binders that update binder kinds of type parameters. -/
#guard_msgs in
structure WithLp (p : Nat) (V : Type) where toLp (m : Int) ::
ofLp : V
end ExC2