@@ -89,6 +89,9 @@ private def assign? (c : Choice) (bidx : Nat) (e : Expr) : OptionT GoalM Choice
8989 -- `Choice` was not properly initialized
9090 unreachable!
9191
92+ private def unassign (c : Choice) (bidx : Nat) : Choice :=
93+ { c with assignment := c.assignment.set! bidx unassigned }
94+
9295/--
9396Returns `true` if the function `pFn` of a pattern is equivalent to the function `eFn`.
9497Recall that we ignore universe levels in patterns.
@@ -290,6 +293,63 @@ private def addNewInstance (thm : EMatchTheorem) (proof : Expr) (generation : Na
290293 trace_goal[grind.ematch.instance] "{← thm.origin.pp}: {prop}"
291294 addTheoremInstance thm proof prop (generation+1 )
292295
296+ private def synthesizeInsts (mvars : Array Expr) (bis : Array BinderInfo) : OptionT M Unit := do
297+ let thm := (← read).thm
298+ for mvar in mvars, bi in bis do
299+ if bi.isInstImplicit && !(← mvar.mvarId!.isAssigned) then
300+ let type ← inferType mvar
301+ unless (← synthesizeInstanceAndAssign mvar type) do
302+ reportIssue! "failed to synthesize instance when instantiating {← thm.origin.pp}{indentExpr type}"
303+ failure
304+
305+ private def applyAssignment (mvars : Array Expr) : OptionT (StateT Choice M) Unit := do
306+ let thm := (← read).thm
307+ let numParams := thm.numParams
308+ for h : i in [:mvars.size] do
309+ let bidx := numParams - i - 1
310+ let mut v := (← get).assignment[bidx]!
311+ unless isSameExpr v unassigned do
312+ let mvarId := mvars[i].mvarId!
313+ let mvarIdType ← mvarId.getType
314+ let vType ← inferType v
315+ let unassignOrFail : OptionT (StateT Choice M) Unit := do
316+ /-
317+ If there is type error and `vType` is a proposition, we can still instantiate the
318+ theorem by unassigning `v` and using it as an extra hypothesis.
319+ Here is an example to motivate the unassignment.
320+ ```
321+ example (xs : Array Nat) (w : xs.reverse = xs) (j : Nat) (hj : 0 ≤ j) (hj' : j < xs.size / 2)
322+ : xs[j] = xs[xs.size - 1 - j] := by
323+ grind
324+ ```
325+ Without the unassignment we get a type error while trying to instantiate the theorem
326+ ```
327+ theorem getElem_reverse {xs : Array α} {i : Nat} (hi : i < xs.reverse.size) :
328+ (xs.reverse)[i] = xs[xs.size - 1 - i]'(by simp at hi; omega)
329+ ```
330+ The pattern for this theorem is `xs.reverese[i]`. Note that `hi` occurs there as an implicit argument.
331+ The term `xs[j]` in our goal e-matches the pattern because we have the equality `xs.reverse = xs`.
332+ However, the implicit proof at `xs[j]` has type `j < xs.size` instead of `j < xs.reverse.size`.
333+ -/
334+ if (← isProp vType) then
335+ modify (unassign · bidx)
336+ else
337+ reportIssue! "type error constructing proof for {← thm.origin.pp}\n when assigning metavariable {mvars[i]} with {indentExpr v}\n {← mkHasTypeButIsExpectedMsg vType mvarIdType}"
338+ failure
339+ unless (← withDefault <| isDefEq mvarIdType vType) do
340+ if let some heq ← withoutReportingMVarIssues <| proveEq? vType mvarIdType (abstract := true ) then
341+ /-
342+ Some of the `cast`s will appear inside the `Grind.MatchCond` binders, and
343+ we want their proofs to be properly wrapped.
344+ -/
345+ let heq := mkApp2 (mkConst ``Grind.nestedProof) (← mkEq vType mvarIdType) heq
346+ v ← mkAppM ``cast #[heq, v]
347+ else
348+ unassignOrFail
349+ continue
350+ unless (← mvarId.checkedAssign v) do
351+ unassignOrFail
352+
293353/--
294354After processing a (multi-)pattern, use the choice assignment to instantiate the proof.
295355Missing parameters are synthesized using type inference and type class synthesis."
@@ -306,35 +366,8 @@ private partial def instantiateTheorem (c : Choice) : M Unit := withDefault do w
306366 if mvars.size != thm.numParams then
307367 reportIssue! "unexpected number of parameters at {← thm.origin.pp}"
308368 return ()
309- -- Apply assignment
310- for h : i in [:mvars.size] do
311- let mut v := c.assignment[numParams - i - 1 ]!
312- unless isSameExpr v unassigned do
313- let mvarId := mvars[i].mvarId!
314- let mvarIdType ← mvarId.getType
315- let vType ← inferType v
316- let report : M Unit := do
317- reportIssue! "type error constructing proof for {← thm.origin.pp}\n when assigning metavariable {mvars[i]} with {indentExpr v}\n {← mkHasTypeButIsExpectedMsg vType mvarIdType}"
318- unless (← withDefault <| isDefEq mvarIdType vType) do
319- let some heq ← withoutReportingMVarIssues <| proveEq? vType mvarIdType (abstract := true )
320- | report
321- return ()
322- /-
323- Some of the `cast`s will appear inside the `Grind.MatchCond` binders, and
324- we want their proofs to be properly wrapped.
325- -/
326- let heq := mkApp2 (mkConst ``Grind.nestedProof) (← mkEq vType mvarIdType) heq
327- v ← mkAppM ``cast #[heq, v]
328- unless (← mvarId.checkedAssign v) do
329- report
330- return ()
331- -- Synthesize instances
332- for mvar in mvars, bi in bis do
333- if bi.isInstImplicit && !(← mvar.mvarId!.isAssigned) then
334- let type ← inferType mvar
335- unless (← synthesizeInstanceAndAssign mvar type) do
336- reportIssue! "failed to synthesize instance when instantiating {← thm.origin.pp}{indentExpr type}"
337- return ()
369+ let (some _, c) ← applyAssignment mvars |>.run c | return ()
370+ let some _ ← synthesizeInsts mvars bis | return ()
338371 let proof := mkAppN proof mvars
339372 if (← mvars.allM (·.mvarId!.isAssigned)) then
340373 addNewInstance thm proof c.gen
0 commit comments