Skip to content

Commit 7e05f55

Browse files
committed
feat: allow several tactics on types that are slightly less obviously Types (#3682)
Many tactics attempt to get the universe of the sort of the terms involved by matching on the level being a succ of something. Unfortunately this fails on some nontrivial examples like mvpolynomial which can have type `Sort (max (u+1) (v+1))` Instead we decrement the level manually after matching it. See https://leanprover.zulipchat.com/#narrow/stream/287929-mathlib4/topic/.60ring.60.20tactic.20cannot.20prove.20equality.20about.20.60MvPolynomial.60/near/352549549 This PR modifies ring, ring_nf, nontriviality, polyrith, linarith, and some norm_num handlers to appropriately handle this. Test cases showing examples that failed before (inspired by the case of mvpolynomial, but in principle there could be other interesting types that have multiple universe parameters in this way, some of which may even have a linear order who knows). In doing so we factor out `inferTypeQ'` into its own file `Mathlib.Tactic.Qq` for mathlib-relevant extensions of Qq
1 parent 7b53c83 commit 7e05f55

File tree

13 files changed

+83
-24
lines changed

13 files changed

+83
-24
lines changed

Mathlib.lean

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2050,6 +2050,7 @@ import Mathlib.Util.IncludeStr
20502050
import Mathlib.Util.LongNames
20512051
import Mathlib.Util.MemoFix
20522052
import Mathlib.Util.Pickle
2053+
import Mathlib.Util.Qq
20532054
import Mathlib.Util.Syntax
20542055
import Mathlib.Util.SynthesizeUsing
20552056
import Mathlib.Util.Tactic

Mathlib/Tactic/Linarith/Verification.lean

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ Ported by: Scott Morrison
77

88
import Mathlib.Tactic.Linarith.Elimination
99
import Mathlib.Tactic.Linarith.Parsing
10+
import Mathlib.Util.Qq
1011

1112
/-!
1213
# Deriving a proof of false
@@ -36,14 +37,6 @@ def ofNatQ (α : Q(Type $u)) (_ : Q(Semiring $α)) (n : ℕ) : Q($α) :=
3637
(q(instAtLeastTwoHAddNatInstHAddInstAddNatOfNat (n := $k)) : Expr)
3738
q(OfNat.ofNat $lit)
3839

39-
/-- Analogue of `inferTypeQ`, but that gets universe levels right for our application. -/
40-
-- See https://leanprover.zulipchat.com/#narrow/stream/287929-mathlib4/topic/Using.20.60QQ.60.20when.20you.20only.20have.20an.20.60Expr.60/near/303349037
41-
def inferTypeQ' (e : Expr) : MetaM ((u : Level) × (α : Q(Type $u)) × Q($α)) := do
42-
let α ← inferType e
43-
let .sort (.succ u) ← instantiateMVars (← whnf (← inferType α))
44-
| throwError "not a type{indentExpr α}"
45-
pure ⟨u, α, e⟩
46-
4740
end Qq
4841

4942
namespace Linarith

Mathlib/Tactic/Nontriviality/Core.lean

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -113,8 +113,9 @@ syntax (name := nontriviality) "nontriviality" (ppSpace (colGt term))?
113113
if let some (α, _) := tgt.app4? ``LT.lt then return α
114114
throwError "The goal is not an (in)equality, so you'll need to specify the desired {""
115115
}`Nontrivial α` instance by invoking `nontriviality α`.")
116-
let .sort (.succ u) ← whnf (← inferType α) | throwError "not a type{indentExpr α}"
117-
let α : Q(Type u) := α
116+
let .sort u ← whnf (← inferType α) | unreachable!
117+
let some v := u.dec | throwError "not a type{indentExpr α}"
118+
let α : Q(Type v) := α
118119
let tac := do
119120
let ty := q(Nontrivial $α)
120121
let m ← mkFreshExprMVar (some ty)

Mathlib/Tactic/NormNum/Basic.lean

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ Authors: Mario Carneiro, Thomas Murrills
66
import Mathlib.Tactic.NormNum.Core
77
import Mathlib.Algebra.GroupPower.Lemmas
88
import Mathlib.Algebra.Order.Invertible
9-
import Qq
9+
import Mathlib.Util.Qq
1010

1111
/-!
1212
## `norm_num` basic plugins
@@ -723,7 +723,7 @@ theorem eq_of_false (ha : ¬a) (hb : ¬b) : a = b := propext (iff_of_false ha hb
723723
such that `norm_num` successfully recognises both `a` and `b`. -/
724724
@[norm_num _ = _, Eq _ _] def evalEq : NormNumExt where eval {u α} e := do
725725
let .app (.app f a) b ← whnfR e | failure
726-
let.succ u, α, a⟩ ← inferTypeQ a | failure
726+
let ⟨u, α, a⟩ ← inferTypeQ' a
727727
have b : Q($α) := b
728728
guard <|← withNewMCtxDepth <| isDefEq f q(Eq (α := $α))
729729
let ra ← derive a; let rb ← derive b
@@ -778,7 +778,7 @@ such that `norm_num` successfully recognises both `a` and `b`. -/
778778
such that `norm_num` successfully recognises both `a` and `b`. -/
779779
@[norm_num _ ≤ _] def evalLE : NormNumExt where eval (e : Q(Prop)) := do
780780
let .app (.app f a) b ← whnfR e | failure
781-
let.succ u, α, a⟩ ← inferTypeQ a | failure
781+
let ⟨u, α, a⟩ ← inferTypeQ' a
782782
have b : Q($α) := b
783783
let ra ← derive a; let rb ← derive b
784784
let intArm (_ : Unit) : MetaM (@Result _ (q(Prop) : Q(Type)) e) := do
@@ -834,7 +834,7 @@ such that `norm_num` successfully recognises both `a` and `b`. -/
834834
such that `norm_num` successfully recognises both `a` and `b`. -/
835835
@[norm_num _ < _] def evalLT : NormNumExt where eval (e : Q(Prop)) := do
836836
let .app (.app f a) b ← whnfR e | failure
837-
let.succ u, α, a⟩ ← inferTypeQ a | failure
837+
let ⟨u, α, a⟩ ← inferTypeQ' a
838838
have b : Q($α) := b
839839
let ra ← derive a; let rb ← derive b
840840
let intArm (_ : Unit) : MetaM (@Result _ (q(Prop) : Q(Type)) e) := do

Mathlib/Tactic/NormNum/Core.lean

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,7 @@ import Mathlib.Data.Rat.Cast
1010
import Mathlib.Data.Nat.Basic
1111
import Mathlib.Data.Int.Basic
1212
import Mathlib.Tactic.Conv
13-
import Qq.MetaM
14-
import Qq.Delab
13+
import Mathlib.Util.Qq
1514

1615
/-!
1716
## `norm_num` core functionality
@@ -619,7 +618,7 @@ def isNormalForm : Expr → Bool
619618
returning a `Simp.Result`. -/
620619
def eval (e : Expr) (post := false) : MetaM Simp.Result := do
621620
if isNormalForm e then return { expr := e }
622-
let.succ _, _, e⟩ ← inferTypeQ e | failure
621+
let ⟨_, _, e⟩ ← inferTypeQ' e
623622
(← derive e post).toSimpResult
624623

625624
/-- Erases a name marked `norm_num` by adding it to the state's `erased` field and

Mathlib/Tactic/Polyrith.lean

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -164,10 +164,11 @@ def parseContext (only : Bool) (hyps : Array Expr) (tgt : Expr) :
164164
AtomM (Expr × Array (Source × Poly) × Poly) := do
165165
let fail {α} : AtomM α := throwError "polyrith failed: target is not an equality in semirings"
166166
let some (α, e₁, e₂) := (← whnfR <|← instantiateMVars tgt).eq? | fail
167-
let .sort (.succ u) ← whnf (← inferType α) | fail
168-
have α : Q(Type u) := α
167+
let .sort u ← instantiateMVars (← whnf (← inferType α)) | unreachable!
168+
let some v := u.dec | throwError "not a type{indentExpr α}"
169+
have α : Q(Type v) := α
169170
have e₁ : Q($α) := e₁; have e₂ : Q($α) := e₂
170-
let sα ← synthInstanceQ (q(CommSemiring $α) : Q(Type u))
171+
let sα ← synthInstanceQ (q(CommSemiring $α) : Q(Type v))
171172
let c ← mkCache sα
172173
let tgt := (← parse sα c e₁).sub (← parse sα c e₂)
173174
let rec

Mathlib/Tactic/Ring/Basic.lean

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1092,10 +1092,11 @@ initialize ringCleanupRef : IO.Ref (Expr → MetaM Expr) ← IO.mkRef pure
10921092
def proveEq (g : MVarId) : AtomM Unit := do
10931093
let some (α, e₁, e₂) := (← whnfR <|← instantiateMVars <|← g.getType).eq?
10941094
| throwError "ring failed: not an equality"
1095-
let .sort (.succ u) ← whnf (← inferType α) | throwError "not a type{indentExpr α}"
1096-
have α : Q(Type u) := α
1095+
let .sort u ← whnf (← inferType α) | unreachable!
1096+
let v ← try u.dec catch _ => throwError "not a type{indentExpr α}"
1097+
have α : Q(Type v) := α
10971098
have e₁ : Q($α) := e₁; have e₂ : Q($α) := e₂
1098-
let sα ← synthInstanceQ (q(CommSemiring $α) : Q(Type u))
1099+
let sα ← synthInstanceQ (q(CommSemiring $α) : Q(Type v))
10991100
let c ← mkCache sα
11001101
profileitM Exception "ring" (← getOptions) do
11011102
let ⟨a, va, pa⟩ ← eval sα c e₁

Mathlib/Tactic/Ring/RingNF.lean

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ Authors: Mario Carneiro, Tim Baanen
55
-/
66
import Mathlib.Tactic.Ring.Basic
77
import Mathlib.Tactic.Conv
8+
import Mathlib.Util.Qq
89

910
/-!
1011
# `ring_nf` tactic
@@ -90,7 +91,7 @@ def rewrite (parent : Expr) (root := true) : M Simp.Result :=
9091
guard <| root || parent != e -- recursion guard
9192
let e ← withReducible <| whnf e
9293
guard e.isApp -- all interesting ring expressions are applications
93-
let.succ u, α, e⟩ ← inferTypeQ e | failure
94+
let ⟨u, α, e⟩ ← inferTypeQ' e
9495
let sα ← synthInstanceQ (q(CommSemiring $α) : Q(Type u))
9596
let c ← mkCache sα
9697
let ⟨a, _, pa⟩ ← match ← isAtomOrDerivable sα c e rctx s with

Mathlib/Util/Qq.lean

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
/-
2+
Copyright (c) 2023 Scott Morrison. All rights reserved.
3+
Released under Apache 2.0 license as described in the file LICENSE.
4+
Authors: Scott Morrison, Alex J. Best
5+
-/
6+
import Qq
7+
8+
/-!
9+
# Extra `Qq` helpers
10+
11+
This file contains some additional functions for using the quote4 library more conveniently.
12+
-/
13+
open Lean Elab Tactic Meta
14+
15+
namespace Qq
16+
17+
/-- Analogue of `inferTypeQ`, but that gets universe levels right for our application. -/
18+
-- See https://leanprover.zulipchat.com/#narrow/stream/287929-mathlib4/topic/Using.20.60QQ.60.20when.20you.20only.20have.20an.20.60Expr.60/near/303349037
19+
def inferTypeQ' (e : Expr) : MetaM ((u : Level) × (α : Q(Type $u)) × Q($α)) := do
20+
let α ← inferType e
21+
let .sort u ← instantiateMVars (← whnf (← inferType α)) | unreachable!
22+
let some v := u.dec | throwError "not a type{indentExpr α}"
23+
pure ⟨v, α, e⟩
24+
25+
end Qq

test/linarith.lean

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -497,3 +497,10 @@ example (n : Nat) (h1 : ¬n = 1) (h2 : n ≥ 1) : n ≥ 2 := by
497497
by_contra h3
498498
suffices n = 1 by exact h1 this
499499
linarith
500+
501+
-- simulate the type of MvPolynomial
502+
def R : Type u → Type v → Sort (max (u+1) (v+1)) := sorry
503+
instance : LinearOrderedField (R c d) := sorry
504+
505+
example (p : R PUnit.{u+1} PUnit.{v+1}) (h : 0 < p) : 0 < 2 * p := by
506+
linarith

0 commit comments

Comments
 (0)