lean4-htt/tests/lean/run/structBinderUpdates.lean
Kyle Miller 5a50a8d278
feat: structure parameter binder kind overrides (#7742)
This PR adds a feature to `structure`/`class` where binders without
types on a field definition are interpreted as overriding the type's
parameters binder kinds in that field's projection function. The rules
are (1) only a prefix of the binders are interpreted this way, (2)
multi-identifier binders are allowed but they must all be for
parameters, (3) only parameters that appear in the declaration itself
(not from `variables`) can be overridden and (4) the updates will be
applied after parameter binder kind inference is done. Binder updates
are not allowed in default value redefinitions. Example application: In
the following, `(R p)` causes the `R` and `p` parameters to be explicit,
where normally they would be implicit.
```
class CharP (R : Type u) [AddMonoidWithOne R] (p : Nat) : Prop where
  cast_eq_zero_iff (R p) : ∀ x : Nat, (x : R) = 0 ↔ p ∣ x


#guard_msgs in #check CharP.cast_eq_zero_iff
/-
info: CharP.cast_eq_zero_iff.{u} (R : Type u) {inst✝ : AddMonoidWithOne R} (p : Nat) [self : CharP R p] (x : Nat) :
  ↑x = 0 ↔ p ∣ x
-/
```
The rationale for (3) is that there are cases where a module starts with
a large `variables` list and a field only incidentally uses the binder.
Without the restriction, the field ends up depending on that variable,
counterintuitively causing it to be introduced as an additional
parameter for the type. Instead, there is an explicit error. The easy
fix is to add `: _`, which is the bare minimum to make the binder have a
type.

We should consider warning when binders shadow parameters.

Closes #3574

[Zulip
discussion](https://leanprover.zulipchat.com/#narrow/channel/270676-lean4/topic/RFC.3A.20adjust.20argument.20explicitness.20on.20typeclass.20projections/near/508584627)

Mathlib fixes:
https://github.com/leanprover-community/mathlib4/pull/23469
2025-03-31 03:54:03 +00:00

136 lines
3.4 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 binder type -/
#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 binder type -/
#guard_msgs in
class C (α : Type) where
β : Type
f (α β) : β
end Ex6