lean4-htt/tests/lean/run/5407.lean
Marc Huisinga 9d427fdfcf
feat: "try this" messages with support for interactivity (#10524)
This PR adds support for interactivity to the combined "try this"
messages that were introduced in #9966. In doing so, it moves the link
to apply a suggestion to a separate `[apply]` button in front of the
suggestion. Hints with diffs remain unchanged, as they did not
previously support interacting with terms in the diff, either.

<img width="379" height="256" alt="Suggestion with interactive message"
src="https://github.com/user-attachments/assets/7838ebf6-0613-46e7-bc88-468a05acbf51"
/>
2025-10-13 13:39:03 +00:00

205 lines
4.9 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.

/-!
# Suggestion tactics should not return invalid tactics
https://github.com/leanprover/lean4/issues/5407
The "suggestion" tactics `exact?`, `apply?`, `show_term`, and `rw?` should not suggest proof terms
that do not compile. They should use `expose_names` where possible to render suggestions valid. If
an invalid proof is generated, these tactics should instead provide users with appropriate feedback.
-/
/-! Discards unprintable implicit argument to lambda -/
inductive Odd : Nat → Prop
| one : Odd 1
| add_two : Odd n → Odd (n + 2)
theorem odd_iff {n : Nat} : Odd n ↔ n % 2 = 1 := by
refine ⟨fun h => by induction h <;> omega, ?_⟩
match n with
| 0 => simp
| 1 => exact fun _ => Odd.one
| n + 2 => exact fun _ => Odd.add_two (odd_iff.mpr (by omega))
/--
error: found a proof, but the corresponding tactic failed:
(expose_names; exact fun a => (fun {n} => odd_iff.mpr) a)
It may be possible to correct this proof by adding type annotations, explicitly specifying implicit arguments, or eliminating unnecessary function abstractions.
-/
#guard_msgs in
example {n : Nat} : n % 2 = 1 → Odd n :=
by exact?
/-! Detects shadowed variables -/
opaque A : Type
opaque B : Type
opaque C : Prop
axiom imp : A → B → C
axiom a : A
axiom b : B
/--
info: Try this:
[apply] (expose_names; exact imp h_1 h)
-/
#guard_msgs in
example : C := by
have h : A := a
have h : B := b
exact?
/-! Detects lambdas with insufficient explicit binder types -/
inductive EqExplicit {α} : αα → Prop
| intro : (a b : α) → a = b → EqExplicit a b
/--
error: found a proof, but the corresponding tactic failed:
(expose_names; exact EqExplicit.intro (fun f => (fun g x => g x) f) id rfl)
It may be possible to correct this proof by adding type annotations, explicitly specifying implicit arguments, or eliminating unnecessary function abstractions.
-/
#guard_msgs in
example : EqExplicit (fun (f : α → β) => (fun g x => g x) f) id := by
exact?
/-! Suggests `expose_names` if a name in the syntax contains macro scopes -/
/--
info: Try this:
[apply] (expose_names; exact h)
-/
#guard_msgs in
example {P : Prop} : P → P := by
intro
exact?
/-! Does *not* suggest `expose_names` when the inaccessible name is an implicit argument. -/
opaque D : Nat → Type
axiom c_of_d {n : Nat} : D n → C
/--
info: Try this:
[apply] exact c_of_d x
-/
#guard_msgs in
example : (n : Nat) → D n → C := by
intro
intro x
exact?
/-! `apply?` logs info instead of erroring -/
opaque E : Prop
axiom option1 : A → E
axiom option2 {_ : B} : E
/--
info: Try this:
[apply] refine option1 ?_
-- Remaining subgoals:
-- ⊢ A
---
info: found a partial proof, but the corresponding tactic failed:
(expose_names; refine option2)
It may be possible to correct this proof by adding type annotations, explicitly specifying implicit arguments, or eliminating unnecessary function abstractions.
---
warning: declaration uses 'sorry'
-/
#guard_msgs in
example : E := by apply?
/-!
This `apply?` erroneously reports a failure if suggesting tactics with dot-focusing notation instead
of parenthesized sequencing.
-/
opaque R : A → B → Prop
axiom rImp (b : B) : R a b → R a b
/--
info: Try this:
[apply] (expose_names; refine rImp b ?_)
-- Remaining subgoals:
-- ⊢ R a b
---
warning: declaration uses 'sorry'
-/
#guard_msgs in
example : (b : B) → R a b := by
intro
apply?
/-! `show_term` exhibits the same behavior as `exact?` -/
/--
info: Try this:
[apply] (expose_names; exact h)
-/
#guard_msgs in
example : E → E := by
intro
show_term assumption
/--
info: found a partial proof, but the corresponding tactic failed:
(expose_names; refine option2)
It may be possible to correct this proof by adding type annotations, explicitly specifying implicit arguments, or eliminating unnecessary function abstractions.
---
error: unsolved goals
a✝ : B
⊢ B
-/
#guard_msgs in
example : B → E := by
intro
show_term apply option2
/--
info: Try this:
[apply] exact c_of_d d
-/
#guard_msgs in
example : (n : Nat) → D n → C := by
intro _ d
show_term apply c_of_d d
/-! `rw?` exhibits the same behavior as above. -/
namespace Rw
opaque A : Type
@[instance] axiom inst : Inhabited A
opaque Foo (a a' : A) : Prop
noncomputable opaque a : A
axiom eq (a' : A) : a = a'
/--
info: Try this:
[apply] (expose_names; rw [eq a'])
-- Foo a' a'
---
error: unsolved goals
a'✝ : A
⊢ Foo a'✝ a'✝
-/
#guard_msgs in
example : (a' : A) → Foo a a' := by
intro
rw?
noncomputable opaque a₁ : A
axiom eq_imp {a' : A} : a₁ = a'
/--
info: found an applicable rewrite lemma, but the corresponding tactic failed:
(expose_names; rw [eq_imp])
-- Foo a' a'
It may be possible to correct this proof by adding type annotations, explicitly specifying implicit arguments, or eliminating unnecessary function abstractions.
---
error: unsolved goals
a'✝ : A
⊢ Foo a'✝ a'✝
-/
#guard_msgs in
example : (a' : A) → Foo a₁ a' := by
intro
rw?