-
Notifications
You must be signed in to change notification settings - Fork 437
/
MkInhabitant.lean
72 lines (67 loc) · 2.74 KB
/
MkInhabitant.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) 2020 Microsoft Corporation. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Leonardo de Moura
-/
prelude
import Lean.Meta.AppBuilder
import Lean.PrettyPrinter
namespace Lean.Elab
open Meta
private def withInhabitedInstances (xs : Array Expr) (k : Array Expr → MetaM α) : MetaM α := do
let rec go (i : Nat) (insts : Array Expr) : MetaM α := do
if h : i < xs.size then
let x := xs[i]
let xTy ← inferType x
let u ← getLevel xTy
let instTy := mkApp (.const ``Inhabited [u]) xTy
let instVal := mkApp2 (.const ``Inhabited.mk [u]) xTy x
withLetDecl `inst instTy instVal fun inst =>
go (i + 1) (insts.push inst)
else
k insts
go 0 #[]
private def mkInhabitant? (type : Expr) (useOfNonempty : Bool) : MetaM (Option Expr) := do
try
if useOfNonempty then
return some (← mkOfNonempty type)
else
return some (← mkDefault type)
catch _ =>
return none
/--
Find an inhabitant while doing delta unfolding.
-/
private partial def mkInhabitantForAux? (xs insts : Array Expr) (type : Expr) (useOfNonempty : Bool) : MetaM (Option Expr) := withIncRecDepth do
if let some val ← mkInhabitant? type useOfNonempty then
mkLambdaFVars xs (← mkLetFVars (usedLetOnly := true) insts val)
else
let type ← whnfCore type
if type.isForall then
forallTelescope type fun xs' type' =>
withInhabitedInstances xs' fun insts' =>
mkInhabitantForAux? (xs ++ xs') (insts ++ insts') type' useOfNonempty
else if let some type' ← unfoldDefinition? type then
mkInhabitantForAux? xs insts type' useOfNonempty
else
return none
/- TODO: add a global IO.Ref to let users customize/extend this procedure -/
def mkInhabitantFor (failedToMessage : MessageData) (xs : Array Expr) (type : Expr) : MetaM Expr :=
withInhabitedInstances xs fun insts => do
if let some val ← mkInhabitantForAux? xs insts type false <||> mkInhabitantForAux? xs insts type true then
return val
else
throwError "\
{failedToMessage}, could not prove that the type\
{indentExpr (← mkForallFVars xs type)}\n\
is nonempty.\n\
\n\
This process uses multiple strategies:\n\
- It looks for a parameter that matches the return type.\n\
- It tries synthesizing '{.ofConstName ``Inhabited}' and '{.ofConstName ``Nonempty}' \
instances for the return type, while making every parameter into a local '{.ofConstName ``Inhabited}' instance.\n\
- It tries unfolding the return type.\n\
\n\
If the return type is defined using the 'structure' or 'inductive' command, \
you can try adding a 'deriving Nonempty' clause to it."
end Lean.Elab