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 ```
152 lines
5.9 KiB
Text
152 lines
5.9 KiB
Text
/-
|
||
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
|