@@ -35,7 +35,7 @@ impl Config {
3535 Ok ( ( ) )
3636 }
3737
38- pub fn build_spec_fn_sig ( prefix : & str , sig : & Signature ) -> Signature {
38+ pub fn build_precondition_fn_sig ( prefix : & str , sig : & Signature ) -> Signature {
3939 Signature {
4040 constness : sig. constness ,
4141 asyncness : sig. asyncness ,
@@ -47,7 +47,30 @@ impl Config {
4747 paren_token : sig. paren_token ,
4848 inputs : sig. inputs . clone ( ) ,
4949 variadic : sig. variadic . clone ( ) ,
50- output : syn:: ReturnType :: Default ,
50+ output : parse_quote ! ( -> bool ) ,
51+ }
52+ }
53+
54+ pub fn build_postcondition_fn_sig ( prefix : & str , sig : & Signature ) -> Signature {
55+ let mut inputs = sig. inputs . clone ( ) ;
56+ let output_binder = match & sig. output {
57+ ReturnType :: Type ( _, return_type) => parse_quote ! ( __anodized_output: & #return_type) ,
58+ ReturnType :: Default => parse_quote ! ( __anodized_output: & ( ) ) ,
59+ } ;
60+ inputs. push ( output_binder) ;
61+
62+ Signature {
63+ constness : sig. constness ,
64+ asyncness : sig. asyncness ,
65+ unsafety : sig. unsafety ,
66+ abi : sig. abi . clone ( ) ,
67+ fn_token : sig. fn_token ,
68+ ident : syn:: Ident :: new ( & format ! ( "{prefix}_{}" , sig. ident) , sig. ident . span ( ) ) ,
69+ generics : sig. generics . clone ( ) ,
70+ paren_token : sig. paren_token ,
71+ inputs,
72+ variadic : sig. variadic . clone ( ) ,
73+ output : parse_quote ! ( -> bool ) ,
5174 }
5275 }
5376
@@ -96,67 +119,88 @@ impl Config {
96119 }
97120 }
98121
99- pub fn build_precondition_fn_body ( conditions : & [ PreCondition ] ) -> Block {
100- let statements = conditions. iter ( ) . map ( |condition| -> Stmt {
122+ pub fn build_precondition_fn_body (
123+ requires : & [ PreCondition ] ,
124+ maintains : & [ PreCondition ] ,
125+ ) -> Block {
126+ let mut statements: Vec < Stmt > = vec ! [ ] ;
127+ let mut clauses: Vec < Expr > = vec ! [ ] ;
128+
129+ for condition in requires. iter ( ) . chain ( maintains) {
130+ let i = clauses. len ( ) ;
131+ let name = Ident :: new ( & format ! ( "__anodized_clause_{}" , i + 1 ) , Span :: mixed_site ( ) ) ;
101132 let closure = & condition. closure ;
102- parse_quote ! { let _ = #closure; }
103- } ) ;
133+ statements. push ( parse_quote ! { let #name = ( #closure) ( ) ; } ) ;
134+ clauses. push ( parse_quote ! { #name } ) ;
135+ }
136+
137+ if clauses. is_empty ( ) {
138+ clauses. push ( parse_quote ! ( true ) ) ;
139+ }
140+
104141 parse_quote ! {
105142 {
106143 #( #statements) *
144+ #( #clauses) &&*
107145 }
108146 }
109147 }
110148
111- pub fn build_poscondition_fn_body (
149+ pub fn build_postcondition_fn_body (
150+ maintains : & [ PreCondition ] ,
112151 captures : & [ Capture ] ,
113- conditions : & [ PostCondition ] ,
152+ ensures : & [ PostCondition ] ,
114153 return_type : & ReturnType ,
115154 ) -> Result < Block > {
116- let aliases = captures. iter ( ) . map ( |capture| & capture. pat ) ;
117- let capture_exprs = captures. iter ( ) . map ( |capture| -> Expr {
118- let expr = & capture. expr ;
119- // Wrap in closure to guard against `return`.
120- parse_quote ! { ( || #expr) ( ) }
121- } ) ;
155+ let mut statements: Vec < Stmt > = vec ! [ ] ;
156+ let mut clauses: Vec < Expr > = vec ! [ ] ;
122157
123- let mut statements = vec ! [ ] ;
158+ for condition in maintains {
159+ let i = clauses. len ( ) ;
160+ let name = Ident :: new ( & format ! ( "__anodized_clause_{}" , i + 1 ) , Span :: mixed_site ( ) ) ;
161+ let closure = & condition. closure ;
162+ statements. push ( parse_quote ! { let #name = ( #closure) ( ) ; } ) ;
163+ clauses. push ( parse_quote ! { #name } ) ;
164+ }
165+
166+ {
167+ let aliases = captures. iter ( ) . map ( |capture| & capture. pat ) ;
168+ let capture_exprs = captures. iter ( ) . map ( |capture| -> Expr {
169+ let expr = & capture. expr ;
170+ // Wrap in closure to guard against `return`.
171+ parse_quote ! { ( || #expr) ( ) }
172+ } ) ;
173+ statements. push ( parse_quote ! { let ( #( #aliases) , * ) = ( #( #capture_exprs) , * ) ; } ) ;
174+ }
124175
125- for condition in conditions {
176+ let output_type = match return_type {
177+ ReturnType :: Type ( _, return_type) => return_type. as_ref ( ) . clone ( ) ,
178+ ReturnType :: Default => parse_quote ! ( ( ) ) ,
179+ } ;
180+ for condition in ensures {
181+ let i = clauses. len ( ) ;
182+ let name = Ident :: new ( & format ! ( "__anodized_clause_{}" , i + 1 ) , Span :: mixed_site ( ) ) ;
126183 let closure = & condition. closure ;
127- // TODO: This sort of validation should happen during parsing.
128- let output_binder = match closure. inputs . first ( ) {
129- Some ( output_binder) if closure. inputs . len ( ) == 1 => output_binder,
130- _ => {
131- return Err ( syn:: Error :: new_spanned (
132- & closure. inputs ,
133- "Postcondition closure must have exactly one parameter." ,
134- ) ) ;
135- }
136- } ;
137- let statement: Stmt = if let Pat :: Type ( _) = output_binder {
138- // If the output binder has a type annotation, use as-is.
139- parse_quote ! { let _ = #closure; }
184+ let input = closure. inputs . first ( ) . expect ( "valid postcondition" ) ;
185+ if let Pat :: Type ( _) = input {
186+ statements. push ( parse_quote ! { let #name = ( #closure) ( __anodized_output) ; } ) ;
140187 } else {
141- // Otherwise add a type annotation.
142188 let body = & closure. body ;
143- let output = & closure. output ;
144- match & return_type {
145- ReturnType :: Default => {
146- parse_quote ! { let _ = |#output_binder: & ( ) | #output { #body } ; }
147- }
148- ReturnType :: Type ( _, ty) => {
149- parse_quote ! { let _ = |#output_binder: & #ty| #output { #body } ; }
150- }
151- }
152- } ;
153- statements. push ( statement) ;
189+ statements. push ( parse_quote ! {
190+ let #name = ( | #input: & #output_type | -> bool { #body } ) ( __anodized_output) ;
191+ } ) ;
192+ }
193+ clauses. push ( parse_quote ! { #name } ) ;
194+ }
195+
196+ if clauses. is_empty ( ) {
197+ clauses. push ( parse_quote ! ( true ) ) ;
154198 }
155199
156200 Ok ( parse_quote ! {
157201 {
158- let ( #( #aliases) , * ) = ( #( #capture_exprs) , * ) ;
159202 #( #statements) *
203+ #( #clauses) &&*
160204 }
161205 } )
162206 }
0 commit comments