forked from leanprover/lean4
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathDecLevel.lean
72 lines (65 loc) · 2.64 KB
/
DecLevel.lean
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
/-
Copyright (c) 2021 Microsoft Corporation. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Leonardo de Moura
-/
import Lean.Meta.Basic
import Lean.Meta.InferType
namespace Lean.Meta
structure DecLevelContext where
/--
If `true`, then `decAux? ?m` returns a fresh metavariable `?n` s.t.
`?m := ?n+1`.
-/
canAssignMVars : Bool := true
private partial def decAux? : Level → ReaderT DecLevelContext MetaM (Option Level)
| Level.zero => return none
| Level.param _ => return none
| Level.mvar mvarId => do
match (← getLevelMVarAssignment? mvarId) with
| some u => decAux? u
| none =>
if (← mvarId.isReadOnly) || !(← read).canAssignMVars then
return none
else
let u ← mkFreshLevelMVar
trace[Meta.isLevelDefEq.step] "decAux?, {mkLevelMVar mvarId} := {mkLevelSucc u}"
assignLevelMVar mvarId (mkLevelSucc u)
return u
| Level.succ u => return u
| u =>
let processMax (u v : Level) : ReaderT DecLevelContext MetaM (Option Level) := do
/- Remark: this code uses the fact that `max (u+1) (v+1) = (max u v)+1`.
`decAux? (max (u+1) (v+1)) := max (decAux? (u+1)) (decAux? (v+1))`
However, we must *not* assign metavariables in the recursive calls since
`max ?u 1` is not equivalent to `max ?v 0` where `?v` is a fresh metavariable, and `?u := ?v+1`
-/
withReader (fun _ => { canAssignMVars := false }) do
match (← decAux? u) with
| none => return none
| some u => do
match (← decAux? v) with
| none => return none
| some v => return mkLevelMax' u v
match u with
| Level.max u v => processMax u v
/- Remark: If `decAux? v` returns `some ...`, then `imax u v` is equivalent to `max u v`. -/
| Level.imax u v => processMax u v
| _ => unreachable!
def decLevel? (u : Level) : MetaM (Option Level) := do
let mctx ← getMCtx
match (← decAux? u |>.run {}) with
| some v => return some v
| none => do
modify fun s => { s with mctx := mctx }
return none
def decLevel (u : Level) : MetaM Level := do
match (← decLevel? u) with
| some u => return u
| none => throwError "invalid universe level, {u} is not greater than 0"
/-- This method is useful for inferring universe level parameters for function that take arguments such as `{α : Type u}`.
Recall that `Type u` is `Sort (u+1)` in Lean. Thus, given `α`, we must infer its universe level,
and then decrement 1 to obtain `u`. -/
def getDecLevel (type : Expr) : MetaM Level := do
decLevel (← getLevel type)
end Lean.Meta