@@ -10,6 +10,11 @@ pub(crate) struct EncodingState {
1010 pub uf_function : HashMap < String , String > ,
1111 /// Maps sort name -> proof function name (set from :internal-proof-func annotation).
1212 pub proof_func_parent : HashMap < String , String > ,
13+ /// Function name -> (hidden current-value function, input arity). The
14+ /// current function uses the original eager backend merge, so cleanup can
15+ /// discard stale proof-view candidates whenever the current value already
16+ /// has a proof witness.
17+ pub merge_current : HashMap < String , ( String , usize ) > ,
1318 pub term_header_added : bool ,
1419 // TODO this is very ugly- we should separate out a typechecking struct
1520 // since we didn't need an entire e-graph
@@ -30,6 +35,7 @@ impl EncodingState {
3035 uf_parent : HashMap :: default ( ) ,
3136 uf_function : HashMap :: default ( ) ,
3237 proof_func_parent : HashMap :: default ( ) ,
38+ merge_current : HashMap :: default ( ) ,
3339 term_header_added : false ,
3440 original_typechecking : None ,
3541 proofs_enabled : false ,
@@ -255,13 +261,25 @@ impl<'a> ProofInstrumentor<'a> {
255261 . as_ref ( )
256262 . unwrap_or_else ( || panic ! ( "Proofs don't support :no-merge" ) ) ;
257263
264+ let current_name = self
265+ . egraph
266+ . parser
267+ . symbol_gen
268+ . fresh ( & format ! ( "{name}Current" ) ) ;
269+ self . egraph
270+ . proof_state
271+ . merge_current
272+ . insert ( name. clone ( ) , ( current_name. clone ( ) , child_names. len ( ) ) ) ;
273+
258274 let fresh_name = self . egraph . parser . symbol_gen . fresh ( "merge_rule" ) ;
259275 let cleanup_name = self . egraph . parser . symbol_gen . fresh ( "merge_cleanup" ) ;
276+ let current_cleanup_name = self . egraph . parser . symbol_gen . fresh ( "merge_current_cleanup" ) ;
260277
261278 let p1_fresh = self . egraph . parser . symbol_gen . fresh ( "p1" ) ;
262279 let p2_fresh = self . egraph . parser . symbol_gen . fresh ( "p2" ) ;
263280 let view_name = self . view_name ( & fdecl. name ) ;
264281 let rebuilding_cleanup_ruleset = self . proof_names ( ) . rebuilding_cleanup_ruleset_name . clone ( ) ;
282+ let input_sorts = ListDisplay ( & fdecl. schema . input , " " ) ;
265283 let proof_query = if self . egraph . proof_state . proofs_enabled {
266284 // View is a function with proof output; bind proof variables
267285 format ! (
@@ -310,7 +328,11 @@ impl<'a> ProofInstrumentor<'a> {
310328 // The first runs the merge function adding a new row.
311329 // The second deletes rows with old values for the old variable, while the third deletes rows with new values for the new variable.
312330 format ! (
313- "(sort {fresh_sort})
331+ "(function {current_name} ({input_sorts}) {output_sort}
332+ :merge {merge_fn}
333+ :unextractable
334+ :internal-hidden)
335+ (sort {fresh_sort})
314336 (constructor {cleanup_constructor} ({output_sort} {output_sort}) {fresh_sort} :internal-hidden)
315337 (rule (({view_name} {child_names_str} old)
316338 ({view_name} {child_names_str} new)
@@ -333,6 +355,13 @@ impl<'a> ProofInstrumentor<'a> {
333355 ((delete ({view_name} {child_names_str} old)))
334356 :ruleset {rebuilding_cleanup_ruleset}
335357 :name \" {cleanup_name}\" )
358+ (rule ((= selected ({current_name} {child_names_str}))
359+ ({view_name} {child_names_str} selected)
360+ ({view_name} {child_names_str} old)
361+ (!= selected old))
362+ ((delete ({view_name} {child_names_str} old)))
363+ :ruleset {rebuilding_cleanup_ruleset}
364+ :name \" {current_cleanup_name}\" )
336365 " ,
337366 )
338367 }
@@ -999,7 +1028,16 @@ impl<'a> ProofInstrumentor<'a> {
9991028 /// View is always a function (returning Proof or Unit).
10001029 fn update_view ( & mut self , fname : & str , args : & [ String ] , proof : & str ) -> String {
10011030 let view_name = self . view_name ( fname) ;
1002- format ! ( "(set ({view_name} {}) {proof})" , ListDisplay ( args, " " ) )
1031+ let view_update = format ! ( "(set ({view_name} {}) {proof})" , ListDisplay ( args, " " ) ) ;
1032+ if let Some ( ( current_name, input_arity) ) =
1033+ self . egraph . proof_state . merge_current . get ( fname) . cloned ( )
1034+ && args. len ( ) == input_arity + 1
1035+ {
1036+ let inputs = ListDisplay ( & args[ ..input_arity] , " " ) ;
1037+ let output = & args[ input_arity] ;
1038+ return format ! ( "{view_update}\n (set ({current_name} {inputs}) {output})" ) ;
1039+ }
1040+ view_update
10031041 }
10041042
10051043 /// Return some code adding to the view and term tables.
0 commit comments