| /- | |
| 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 |