This PR refactors the 'ext' attribute and implements the following features: - The 'local' and 'scoped' attribute kinds are now usable. - The attribute realizes the `ext`/`ext_iff` lemmas when they do not already exist, rather than always generating them. This is useful in conjunction with `@[local ext]`. - Adding `@[ext]` to a user ext lemma now realizes an `ext_iff` lemma as well; formerly this was only for structures. The name of the generated `ext_iff` theorem for a user `ext` theorem named `A.B.myext` is `A.B.myext_iff`. If this process leads to an error, the user can write `@[ext (iff := false)]` to disable this feature. Breaking changes: - Now the "x" and "y" term arguments to the realized `ext` and `ext_iff` lemmas are implicit. - Now the realized `ext` and `ext_iff` lemmas are protected. Bootstrapping notes: - There are a few `ext_iff` lemmas to address after the next stage0 update. Closes https://github.com/leanprover/lean4/issues/3643 Suggested by Floris [on Zulip](https://leanprover.zulipchat.com/#narrow/stream/113488-general/topic/.22Missing.20Tactics.22.20list/near/446267660).
128 lines
2.3 KiB
Text
128 lines
2.3 KiB
Text
|
||
import Lean
|
||
/-!
|
||
# Make sure 'ext' attribute works in conjuction with local/scoped
|
||
-/
|
||
|
||
section Ex0
|
||
|
||
@[local ext] structure S (α β : Type _) where
|
||
a : α
|
||
b : β
|
||
|
||
-- Used to fail
|
||
attribute [local ext] S
|
||
|
||
-- Used to work, still works
|
||
attribute [local ext] S.ext
|
||
|
||
/--
|
||
info: S.ext.{u_1, u_2} {α : Type u_1} {β : Type u_2} {x y : S α β} (a : x.a = y.a) (b : x.b = y.b) : x = y
|
||
-/
|
||
#guard_msgs in #check S.ext
|
||
|
||
/--
|
||
info: S.ext_iff.{u_1, u_2} {α : Type u_1} {β : Type u_2} {x y : S α β} : x = y ↔ x.a = y.a ∧ x.b = y.b
|
||
-/
|
||
#guard_msgs in #check S.ext_iff
|
||
|
||
end Ex0
|
||
|
||
|
||
section Ex1
|
||
|
||
section
|
||
|
||
@[local ext] structure S1 (α β : Type _) where
|
||
a : α
|
||
b : β
|
||
|
||
/--
|
||
info: S1.ext.{u_1, u_2} {α : Type u_1} {β : Type u_2} {x y : S1 α β} (a : x.a = y.a) (b : x.b = y.b) : x = y
|
||
-/
|
||
#guard_msgs in #check S1.ext
|
||
|
||
example (x y : S1 Unit Unit) : x = y := by ext
|
||
|
||
end
|
||
|
||
/--
|
||
error: no applicable extensionality theorem found for
|
||
S1 Unit Unit
|
||
-/
|
||
#guard_msgs in example (x y : S1 Unit Unit) : x = y := by ext
|
||
|
||
end Ex1
|
||
|
||
|
||
section Ex2
|
||
|
||
structure S2 (α β : Type _) where
|
||
a : α
|
||
b : β
|
||
|
||
section
|
||
|
||
@[local ext] private theorem S2_ext {x y : S2 α β} (a : x.a = y.a) (b : x.b = y.b) : x = y := by
|
||
cases x
|
||
cases y
|
||
subst_vars
|
||
rfl
|
||
|
||
example (x y : S2 Unit Unit) : x = y := by ext
|
||
|
||
end
|
||
|
||
/--
|
||
error: no applicable extensionality theorem found for
|
||
S2 Unit Unit
|
||
-/
|
||
#guard_msgs in example (x y : S2 Unit Unit) : x = y := by ext
|
||
|
||
/--
|
||
info: S2_ext_iff.{u_1, u_2} {α : Type u_1} {β : Type u_2} {x y : S2 α β} : x = y ↔ x.a = y.a ∧ x.b = y.b
|
||
-/
|
||
#guard_msgs in #check S2_ext_iff
|
||
|
||
end Ex2
|
||
|
||
|
||
section Ex3
|
||
|
||
-- TODO: allow 'scoped' here? The limitation is in attribute processing itself, not the 'ext' attribute.
|
||
/-- error: scoped attributes must be used inside namespaces -/
|
||
#guard_msgs in
|
||
@[scoped ext] structure S3' (α β : Type _) where
|
||
a : α
|
||
b : β
|
||
|
||
structure S3 (α β : Type _) where
|
||
a : α
|
||
b : β
|
||
|
||
namespace S3
|
||
attribute [scoped ext] S3
|
||
|
||
/--
|
||
info: S3.ext.{u_1, u_2} {α : Type u_1} {β : Type u_2} {x y : S3 α β} (a : x.a = y.a) (b : x.b = y.b) : x = y
|
||
-/
|
||
#guard_msgs in #check S3.ext
|
||
|
||
example (x y : S3 Unit Unit) : x = y := by
|
||
ext
|
||
|
||
end S3
|
||
|
||
/--
|
||
error: no applicable extensionality theorem found for
|
||
S3 Unit Unit
|
||
-/
|
||
#guard_msgs in
|
||
example (x y : S3 Unit Unit) : x = y := by
|
||
ext
|
||
|
||
open scoped S3 in
|
||
example (x y : S3 Unit Unit) : x = y := by
|
||
ext
|
||
|
||
end Ex3
|