lean4-htt/tests/elab/solve_by_elim.lean
Wojciech Różowski 91dd99165a
feat: add warning when applying global attribute using in (#13223)
This PR adds a warning preventing a user from applying global attribute
using `... in ...`, e.g.
```lean4
theorem a : True := trivial
attribute [simp] a in
def b : True := a
```
2026-04-08 06:20:34 +00:00

152 lines
5.9 KiB
Text
Raw Permalink 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.

/-
Copyright (c) 2021 Kim Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Kim Morrison
-/
import Lean.Meta.Tactic.Constructor
import Lean.Elab.SyntheticMVars
import Lean.Elab.Tactic.SolveByElim -- FIXME we need to make SolveByElimConfig builtin
set_option autoImplicit true
example (h : Nat) : Nat := by solve_by_elim
example {α β : Type} (f : α → β) (a : α) : β := by solve_by_elim
example {α β : Type} (f : αα → β) (a : α) : β := by solve_by_elim
example {α β γ : Type} (f : α → β) (g : β → γ) (a : α) : γ := by solve_by_elim
example {α β γ : Type} (_f : α → β) (g : β → γ) (b : β) : γ := by solve_by_elim
example {α : Nat → Type} (f : (n : Nat) → α n → α (n+1)) (a : α 0) : α 4 := by solve_by_elim
example (h : Nat) : Nat := by solve_by_elim []
example {α β : Type} (f : α → β) (a : α) : β := by solve_by_elim []
example {α β : Type} (f : αα → β) (a : α) : β := by solve_by_elim []
example {α β γ : Type} (f : α → β) (g : β → γ) (a : α) : γ := by solve_by_elim []
example {α β γ : Type} (_f : α → β) (g : β → γ) (b : β) : γ := by solve_by_elim []
example {α : Nat → Type} (f : (n : Nat) → α n → α (n+1)) (a : α 0) : α 4 := by solve_by_elim []
example {α β : Type} (f : α → β) (a : α) : β := by
fail_if_success solve_by_elim [-f]
fail_if_success solve_by_elim [-a]
fail_if_success solve_by_elim only [f]
solve_by_elim
example {α β γ : Type} (f : α → β) (g : β → γ) (b : β) : γ := by
fail_if_success solve_by_elim [-g]
solve_by_elim [-f]
example (h : Nat) : Nat := by solve_by_elim only [h]
example {α β : Type} (f : α → β) (a : α) : β := by solve_by_elim only [f, a]
example {α β : Type} (f : αα → β) (a : α) : β := by solve_by_elim only [f, a]
example {α β γ : Type} (f : α → β) (g : β → γ) (a : α) : γ := by solve_by_elim only [f, g, a]
example {α β γ : Type} (_f : α → β) (g : β → γ) (b : β) : γ := by solve_by_elim only [g, b]
example {α : Nat → Type} (f : (n : Nat) → α n → α (n+1)) (a : α 0) : α 4 := by
solve_by_elim only [f, a]
set_option linter.unusedVariables false in
example (h₁ h₂ : False) : True := by
-- 'It doesn't make sense to remove local hypotheses when using `only` without `*`.'
fail_if_success solve_by_elim only [-h₁]
-- 'It does make sense to use `*` without `only`.'
fail_if_success solve_by_elim [*, -h₁]
solve_by_elim only [*, -h₁]
-- Verify that already assigned metavariables are skipped.
example (P₁ P₂ : α → Prop) (f : ∀ (a : α), P₁ a → P₂ a → β)
(a : α) (ha₁ : P₁ a) (ha₂ : P₂ a) : β := by
solve_by_elim
example {X : Type} (x : X) : x = x := by
fail_if_success solve_by_elim (config := {constructor := false}) only -- needs the `rfl` lemma
solve_by_elim
-- Needs to apply `rfl` twice, with different implicit arguments each time.
-- A naive implementation of solve_by_elim would get stuck.
example {X : Type} (x y : X) (p : Prop) (h : x = x → y = y → p) : p := by solve_by_elim
example : True := by
fail_if_success solve_by_elim (config := {constructor := false}) only -- needs the `trivial` lemma
solve_by_elim
-- Requires backtracking.
example (P₁ P₂ : α → Prop) (f : ∀ (a: α), P₁ a → P₂ a → β)
(a : α) (_ha₁ : P₁ a)
(a' : α) (ha'₁ : P₁ a') (ha'₂ : P₂ a') : β := by
fail_if_success solve_by_elim (config := .noBackTracking)
solve_by_elim
attribute [symm] Eq.symm
example {α : Type} {a b : α → Prop} (h₀ : b = a) (y : α) : a y = b y := by
fail_if_success solve_by_elim (config := {symm := false})
solve_by_elim
example (P : True → False) : 3 = 7 := by
fail_if_success solve_by_elim (config := {exfalso := false})
solve_by_elim
-- Verifying that `solve_by_elim` acts only on the main goal.
example (n : Nat) : Nat × Nat := by
constructor
solve_by_elim
solve_by_elim
-- Verifying that `solve_by_elim*` acts on all remaining goals.
example (n : Nat) : Nat × Nat := by
constructor
solve_by_elim*
open Lean Elab Tactic in
/--
`fconstructor` is like `constructor`
(it calls `apply` using the first matching constructor of an inductive datatype)
except that it does not reorder goals.
-/
elab "fconstructor" : tactic => withMainContext do
let mvarIds' ← (← getMainGoal).constructor {newGoals := .all}
Term.synthesizeSyntheticMVarsNoPostponing
replaceMainGoal mvarIds'
-- Verifying that `solve_by_elim*` backtracks when given multiple goals.
example (n m : Nat) (f : Nat → Nat → Prop) (h : f n m) : ∃ p : Nat × Nat, f p.1 p.2 := by
fconstructor
fconstructor
solve_by_elim*
-- test that metavariables created for implicit arguments don't get stuck
example (P : Nat → Type) (f : {n : Nat} → P n) : P 2 × P 3 := by
fconstructor
solve_by_elim* only [f]
example : 6 = 6 ∧ [7] = [7] := by
fconstructor
solve_by_elim* only [@rfl _]
-- Test that `Config.intros` causes `solve_by_elim` to call `intro` on intermediate goals.
example (P : Prop) : P → P := by
fail_if_success solve_by_elim (config := {intro := false})
solve_by_elim
-- This worked in mathlib3 without the `@`, but now goes into a loop.
-- If someone wants to diagnose this, please do!
example (P Q : Prop) : P ∧ Q → P ∧ Q := by
solve_by_elim [And.imp, @id]
section apply_assumption
example {a b : Type} (h₀ : a → b) (h₁ : a) : b := by
apply_assumption
apply_assumption
example {α : Type} {p : α → Prop} (h₀ : ∀ x, p x) (y : α) : p y := by
apply_assumption
-- Check that `apply_assumption` uses `exfalso`.
example {P Q : Prop} (p : P) (q : Q) (h : P → ¬ Q) : Nat := by
fail_if_success apply_assumption (config := {exfalso := false})
apply_assumption <;> assumption
end apply_assumption
example (x : (α ×× γ))) : (α × β) × γ := by
rcases x with ⟨a, b, c⟩
fail_if_success solve_by_elim (config := {constructor := false})
solve_by_elim