@@ -102,11 +102,15 @@ def sorries (trees : List InfoTree) (env? : Option Environment) (rootGoals? : Op
102102 fun ⟨ctx, g, pos, endPos⟩ => do
103103 let (goal, proofState) ← match g with
104104 | .tactic g => do
105- let s ← ProofSnapshot.create ctx none env? [g] rootGoals?
106- pure ("\n " .intercalate <| (← s.ppGoals).map fun s => s! "{ s} " , some s)
105+ let lctx ← ctx.runMetaM {} do
106+ match ctx.mctx.findDecl? g with
107+ | some decl => return decl.lctx
108+ | none => throwError "unknown metavariable '{g}'"
109+ let s ← ProofSnapshot.create ctx lctx env? [g] rootGoals?
110+ pure ("\n " .intercalate <| (← s.ppGoals).map fun s => s! "{ s} " , some s)
107111 | .term lctx (some t) => do
108- let s ← ProofSnapshot.create ctx lctx env? [] rootGoals? [t]
109- pure ("\n " .intercalate <| (← s.ppGoals).map fun s => s! "{ s} " , some s)
112+ let s ← ProofSnapshot.create ctx lctx env? [] rootGoals? [t]
113+ pure ("\n " .intercalate <| (← s.ppGoals).map fun s => s! "{ s} " , some s)
110114 | .term _ none => unreachable!
111115 let proofStateId ← proofState.mapM recordProofSnapshot
112116 return Sorry.of goal pos endPos proofStateId
@@ -117,23 +121,55 @@ def ppTactic (ctx : ContextInfo) (stx : Syntax) : IO Format :=
117121 catch _ =>
118122 pure "<failed to pretty print>"
119123
120- def tactics (trees : List InfoTree) : M m (List Tactic) :=
124+ def tactics (trees : List InfoTree) (env? : Option Environment) : M m (List Tactic) :=
121125 trees.flatMap InfoTree.tactics |>.mapM
122126 fun ⟨ctx, stx, rootGoals, goals, pos, endPos, ns⟩ => do
123- let proofState := some (← ProofSnapshot.create ctx none none goals rootGoals)
127+ let proofState := some (← ProofSnapshot.create ctx none env? goals rootGoals)
124128 let goals := s! "{ (← ctx.ppGoals goals)} " .trim
125129 let tactic := Format.pretty (← ppTactic ctx stx)
126130 let proofStateId ← proofState.mapM recordProofSnapshot
127131 return Tactic.of goals tactic pos endPos proofStateId ns
128132
129- def collectRootGoalsAsSorries (trees : List InfoTree) : M m (List Sorry) := do
133+ def collectRootGoalsAsSorries (trees : List InfoTree) (env? : Option Environment) : M m (List Sorry) := do
130134 trees.flatMap InfoTree.rootGoals |>.mapM
131135 fun ⟨ctx, goals, pos⟩ => do
132- let proofState := some (← ProofSnapshot.create ctx none none goals goals)
136+ let proofState := some (← ProofSnapshot.create ctx none env? goals goals)
133137 let goals := s! "{ (← ctx.ppGoals goals)} " .trim
134138 let proofStateId ← proofState.mapM recordProofSnapshot
135139 return Sorry.of goals pos pos proofStateId
136140
141+
142+ private def collectFVarsAux : Expr → NameSet
143+ | .fvar fvarId => NameSet.empty.insert fvarId.name
144+ | .app fm arg => (collectFVarsAux fm).union $ collectFVarsAux arg
145+ | .lam _ binderType body _ => (collectFVarsAux binderType).union $ collectFVarsAux body
146+ | .forallE _ binderType body _ => (collectFVarsAux binderType).union $ collectFVarsAux body
147+ | .letE _ type value body _ => ((collectFVarsAux type).union $ collectFVarsAux value).union $ collectFVarsAux body
148+ | .mdata _ expr => collectFVarsAux expr
149+ | .proj _ _ struct => collectFVarsAux struct
150+ | _ => NameSet.empty
151+
152+ /-- Collect all fvars in the expression, and return their names. -/
153+ private def collectFVars (e : Expr) : MetaM (Array Expr) := do
154+ let names := collectFVarsAux e
155+ let mut fvars := #[]
156+ for ldecl in ← getLCtx do
157+ if ldecl.isImplementationDetail then
158+ continue
159+ if names.contains ldecl.fvarId.name then
160+ fvars := fvars.push $ .fvar ldecl.fvarId
161+ return fvars
162+
163+
164+ private def abstractAllLambdaFVars (e : Expr) : MetaM Expr := do
165+ let mut e' := e
166+ while e'.hasFVar do
167+ let fvars ← collectFVars e'
168+ if fvars.isEmpty then
169+ break
170+ e' ← Meta.mkLambdaFVars fvars e'
171+ return e'
172+
137173/--
138174Evaluates the current status of a proof, returning a string description.
139175Main states include:
@@ -153,25 +189,39 @@ def getProofStatus (proofState : ProofSnapshot) : M m String := do
153189 | none => return "Error: Goal not assigned"
154190 | some pf => do
155191 let pf ← instantiateMVars pf
192+
193+ -- First check that the proof has the expected type
156194 let pft ← Meta.inferType pf >>= instantiateMVars
157- if pf.hasSorry then
158- return "Incomplete: contains sorry"
195+ let expectedType ← Meta.inferType (mkMVar goalId) >>= instantiateMVars
196+ unless (← Meta.isDefEq pft expectedType) do
197+ return s! "Error: proof has type { pft} but root goal has type { expectedType} "
198+
199+ let pf ← goalId.withContext $ abstractAllLambdaFVars pf
200+ let pft ← Meta.inferType pf >>= instantiateMVars
201+
159202 if pf.hasExprMVar then
160203 return "Incomplete: contains metavariable(s)"
161204
162- let decl := Declaration.defnDecl ({
205+ -- Find all level parameters
206+ let usedLevels := collectLevelParams {} pft
207+ let usedLevels := collectLevelParams usedLevels pf
208+
209+ let decl := Declaration.defnDecl {
163210 name := Name.anonymous,
164211 type := pft,
165212 value := pf,
166- levelParams := (collectLevelParams {} pft) .params.toList,
213+ levelParams := usedLevels .params.toList,
167214 hints := ReducibilityHints.opaque,
168215 safety := DefinitionSafety.safe
169- })
216+ }
170217
171218 try
172219 let _ ← addDecl decl
173220 catch ex =>
174221 return s! "Error: kernel type check failed: { ← ex.toMessageData.toString} "
222+
223+ if pf.hasSorry then
224+ return "Incomplete: contains sorry"
175225 return "Completed"
176226
177227 | _ => return "Not verified: more than one initial goal"
@@ -251,19 +301,19 @@ def runCommand (s : Command) : M IO (CommandResponse ⊕ Error) := do
251301 if notFound then
252302 return .inr ⟨"Unknown environment." ⟩
253303 let initialCmdState? := cmdSnapshot?.map fun c => c.cmdState
254- let (cmdState, messages, trees) ← try
304+ let (initialCmdState, cmdState, messages, trees) ← try
255305 IO.processInput s.cmd initialCmdState?
256306 catch ex =>
257307 return .inr ⟨ex.toString⟩
258308 let messages ← messages.mapM fun m => Message.of m
259309 -- For debugging purposes, sometimes we print out the trees here:
260310 -- trees.forM fun t => do IO.println (← t.format)
261- let sorries ← sorries trees ( initialCmdState?.map (·. env)) none
311+ let sorries ← sorries trees initialCmdState. env none
262312 let sorries ← match s.rootGoals with
263- | some true => pure (sorries ++ (← collectRootGoalsAsSorries trees))
313+ | some true => pure (sorries ++ (← collectRootGoalsAsSorries trees initialCmdState.env ))
264314 | _ => pure sorries
265315 let tactics ← match s.allTactics with
266- | some true => tactics trees
316+ | some true => tactics trees initialCmdState.env
267317 | _ => pure []
268318 let cmdSnapshot :=
269319 { cmdState
0 commit comments