1+ """
2+
3+ Contracts are a database of lemmas associated with a function symbol.
4+ They are usually used to specify intended pre and postconditions for functions as an abstraction over their definition.
5+ This can also be though of as a subtyping refinement.
6+
7+ There is a registry which can be queried.
8+
9+ This registry is not trusted code.
10+
11+ """
12+
113from dataclasses import dataclass
214import kdrag .smt as smt
315import kdrag as kd
@@ -9,21 +21,17 @@ class Contract:
921 args : list [smt .ExprRef ]
1022 pre : smt .BoolRef
1123 post : smt .BoolRef
12- proof : kd .Proof
24+ proof : kd .kernel . Proof
1325
1426
1527contracts : dict [smt .FuncDeclRef , Contract ] = {}
1628
17- """
18- def add_contract(f: smt.FuncDeclRef, proof: kd.Proof):
19- assert f not in contracts
20- contracts[f] = proof
21- """
2229
23-
24- def lemmas (e : smt .ExprRef ) -> list [kd .Proof ]:
30+ def lemmas (e : smt .ExprRef , into_binders = True ) -> list [kd .kernel .Proof ]:
2531 """
26- Instantiate all contract lemmas found in
32+ Instantiate all contract lemmas found in a pexression.
33+ This sweeps the expression and instantiates the contract lemma with the arguments to the function.
34+ Once it goes under binders, this becomes more difficult, so it returns the quantified form of the lemmas
2735 """
2836 res = []
2937 seen : set [int ] = set ([e .get_id ()])
@@ -44,7 +52,8 @@ def lemmas(e: smt.ExprRef) -> list[kd.Proof]:
4452 todo .append (c )
4553 elif isinstance (e , smt .QuantifierRef ):
4654 # There may be variables inside here. Fallback to just giving z3
47- decls .update (kd .utils .decls (e .body ()))
55+ if into_binders :
56+ decls .update (kd .utils .decls (e .body ()))
4857 else :
4958 raise ValueError (f"Unexpected term type: { e } " )
5059 res .extend (contracts [decl ].proof for decl in decls if decl in contracts )
@@ -53,7 +62,7 @@ def lemmas(e: smt.ExprRef) -> list[kd.Proof]:
5362
5463def contract (
5564 f : smt .FuncDeclRef , args : list [smt .ExprRef ], pre , post , by = None , ** kwargs
56- ) -> kd .Proof :
65+ ) -> kd .kernel . Proof :
5766 """
5867 Register the contract for function f: for all args, pre => post.
5968
@@ -64,28 +73,21 @@ def contract(
6473 |= ForAll(x, Implies(x > 0, foo4392(x) > 0))
6574 >>> c.thm.pattern(0)
6675 foo4392(Var(0))
67- >>> prove(foo(5) > 0)
76+ >>> kd. prove(foo(5) > 0, contracts=True )
6877 |= foo4392(5) > 0
69- >>> prove(foo(5) > 5)
78+ >>> kd. prove(foo(5) > 5, contracts=True )
7079 Traceback (most recent call last):
7180 ...
7281 LemmaError: ...
7382 """
7483 assert f not in contracts
7584 if by is None :
76- by = lemmas ( pre ) + lemmas ( post )
77- else :
78- by = by + lemmas (pre ) + lemmas ( post )
79- pf = kd .prove (smt . ForAll ( args , pre , post , patterns = [ f ( * args )]), by = by , ** kwargs )
85+ by = []
86+ thm = smt . ForAll ( args , smt . Implies ( pre , post ), patterns = [ f ( * args )])
87+ by = by + lemmas (thm )
88+ pf = kd .kernel . prove (thm , by = by , ** kwargs ) # Do we want kd.tactics.prove here?
8089 contracts [f ] = Contract (f , args , pre , post , pf )
8190 return pf
8291
8392
84- # def define(name, args, body, pre=None, post=None): ...
85-
86-
87- def prove (thm : smt .BoolRef , by = [], ** kwargs ) -> kd .Proof :
88- by = by + [
89- contracts [decl ].proof for decl in kd .utils .decls (thm ) if decl in contracts
90- ]
91- return kd .prove (thm , by = by , ** kwargs )
93+ # Special define?
0 commit comments