@@ -201,7 +201,7 @@ impl<'s, T: Debug, Unif: UnifierTop> Drop for Substitutor<'s, T, Unif> {
201201 fn drop ( & mut self ) {
202202 if !std:: thread:: panicking ( ) && self . ready_constraints . take ( ) . is_some ( ) {
203203 panic ! (
204- "Substitutor dropped while still holding Ready Constraints! These should have been resolved using [Unifier ::execute_ready_constraints]"
204+ "Substitutor dropped while still holding Ready Constraints! These should have been resolved using [Substitutor ::execute_ready_constraints]"
205205 ) ;
206206 }
207207 }
@@ -222,6 +222,25 @@ impl<'s, T: Debug, Unif: UnifierTop> Substitutor<'s, T, Unif> {
222222 self . ready_constraints
223223 . set ( DelayedConstraint :: add_to_list ( long_list, constraints) ) ;
224224 }
225+
226+ /// See [UnifierTop::delayed_constraint]
227+ ///
228+ /// We bubble delayed constraints up to the top of the call stack,
229+ /// because if we immediately execute any delayed constraint that becomes ready,
230+ /// we might blow out the stack.
231+ ///
232+ /// You may call [Substitutor::execute_ready_constraints] multiple times, but certainly you must make sure to call it before the [UnifierTop] is dropped.
233+ fn execute_ready_constraints ( & self , unif : & Unif ) {
234+ // During of a delayed constraint, other constraints may of course become ready.
235+ // We retry delayed constraints in a stack-like manner, as my intuition tells me this is more efficient.
236+ while let Some ( mut first_constraint) = self . ready_constraints . take ( ) {
237+ self . ready_constraints . set ( first_constraint. next . take ( ) ) ;
238+
239+ if let Err ( resolution_err) = ( first_constraint. f ) ( unif) {
240+ resolution_err. add_delayed_constraint ( first_constraint) ;
241+ }
242+ }
243+ }
225244}
226245
227246impl < ' s , T : Debug , Unif : UnifierTop > SubstitutorInterior < ' s , T , Unif > {
@@ -328,7 +347,7 @@ pub struct SubTree<T>(usize, PhantomData<T>);
328347/// going through the trouble with &mut refs is not worth it. Passing it along the call stack is also no bueno,
329348/// we'd have to pass the unifier itself, plus whatever extra data the user wants to attach to it. Lots of complexity for nothing.
330349///
331- /// Times we've been through the `&mut Substitutor` dead-end thus far: 3
350+ /// Times we've been through the `&mut Substitutor` dead-end thus far: 4
332351pub trait Unifier < ' slf , ' s : ' slf , T : Debug + Clone + ' s > : UnifierTop + Sized + ' s {
333352 /// You should declare a [Substitutor] field for each [UniCell]`<T>` you wish to support. Return it here.
334353 fn get_substitutor ( & ' slf self ) -> & ' slf Substitutor < ' s , T , Self > ;
@@ -560,38 +579,24 @@ pub trait Unifier<'slf, 's: 'slf, T: Debug + Clone + 's>: UnifierTop + Sized + '
560579 Err ( None ) => false ,
561580 }
562581 }
563-
564- /// See [UnifierTop::delayed_constraint]
565- ///
566- /// We bubble delayed constraints up to the top of the call stack,
567- /// because if we immediately execute any delayed constraint that becomes ready,
568- /// we might blow out the stack.
569- fn execute_ready_constraints ( & ' slf self ) {
570- let subs = self . get_substitutor ( ) ;
571- // During of a delayed constraint, other constraints may of course become ready.
572- // We retry delayed constraints in a stack-like manner, as my intuition tells me this is more efficient.
573- while let Some ( mut first_constraint) = subs. ready_constraints . take ( ) {
574- subs. ready_constraints . set ( first_constraint. next . take ( ) ) ;
575-
576- if let Err ( resolution_err) = ( first_constraint. f ) ( self ) {
577- resolution_err. add_delayed_constraint ( first_constraint) ;
578- }
579- }
580- }
581582}
582583
583584pub trait UnifierTop : Sized {
584- /// When using [UnifierTop::delayed_constraint],
585- /// you must also call [Unifier::execute_ready_constraints] once, or multiple times.
586- fn delayed_constraint < ' slf2 , ' s : ' slf2 > (
587- & ' slf2 self ,
588- mut f : impl for < ' slf > FnMut ( & ' slf Self ) -> Result < ( ) , ResolveError < ' slf , ' s , Self > > + ' s ,
585+ /// You must call [UnifierTop::execute_ready_constraints] after creating delayed_constraints,
586+ /// as not immediately resolved delayed constraints don't immediately get resolved the moment they become eligible.
587+ fn delayed_constraint < ' slf , ' s : ' slf > (
588+ & ' slf self ,
589+ mut f : impl for < ' fn_slf > FnMut ( & ' fn_slf Self ) -> Result < ( ) , ResolveError < ' fn_slf , ' s , Self > >
590+ + ' s ,
589591 ) {
590592 if let Err ( not_found_var) = f ( self ) {
591593 // May be a not_found_var from a different Substitutor
592594 not_found_var. add_delayed_constraint ( Box :: new ( DelayedConstraint { next : None , f } ) ) ;
593595 }
594596 }
597+ /// This method is provided as a reminder that [Substitutor::execute_ready_constraints] must be called for all [Substitutor]s that are part of this [UnifierTop].
598+ /// You may call [UnifierTop::execute_ready_constraints] multiple times, but certainly you must make sure to call it before the [UnifierTop] is dropped.
599+ fn execute_ready_constraints ( & self ) ;
595600}
596601
597602/// Fancy trick! [Rust Forum - Creating a DST struct with a dyn FnMut](https://users.rust-lang.org/t/creating-a-dst-struct-with-a-dyn-fnmut/137256/3).
@@ -701,23 +706,42 @@ impl PeanoType {
701706 }
702707}
703708
709+ #[ derive( Debug , Clone ) ]
710+ enum SecondType {
711+ None ,
712+ OnePeano ( UniCell < PeanoType > ) ,
713+ TwoPeano ( UniCell < PeanoType > , UniCell < PeanoType > ) ,
714+ }
715+
716+ impl SecondType {
717+ #[ allow( clippy:: declare_interior_mutable_const) ]
718+ pub const UNKNOWN : UniCell < SecondType > = UniCell :: < SecondType > :: UNKNOWN ;
719+ }
720+
704721#[ derive( Debug ) ]
705722struct PeanoUnifier < ' s > {
706- substitutor : Substitutor < ' s , PeanoType , Self > ,
723+ peano_subs : Substitutor < ' s , PeanoType , Self > ,
724+ second_subs : Substitutor < ' s , SecondType , Self > ,
707725}
708726
709727impl < ' s > PeanoUnifier < ' s > {
710728 pub fn new ( ) -> Self {
711729 Self {
712- substitutor : Substitutor :: new ( ) ,
730+ peano_subs : Substitutor :: new ( ) ,
731+ second_subs : Substitutor :: new ( ) ,
713732 }
714733 }
715734}
716735
717- impl < ' s > UnifierTop for PeanoUnifier < ' s > { }
736+ impl < ' s > UnifierTop for PeanoUnifier < ' s > {
737+ fn execute_ready_constraints ( & self ) {
738+ self . peano_subs . execute_ready_constraints ( self ) ;
739+ self . second_subs . execute_ready_constraints ( self ) ;
740+ }
741+ }
718742impl < ' slf , ' s : ' slf > Unifier < ' slf , ' s , PeanoType > for PeanoUnifier < ' s > {
719743 fn get_substitutor ( & ' slf self ) -> & ' slf Substitutor < ' s , PeanoType , Self > {
720- & self . substitutor
744+ & self . peano_subs
721745 }
722746 fn unify_subtrees ( & ' slf self , a : & ' s PeanoType , b : & ' s PeanoType ) -> UnifyResult {
723747 match ( a, b) {
@@ -755,6 +779,57 @@ impl<'slf, 's: 'slf> Unifier<'slf, 's, PeanoType> for PeanoUnifier<'s> {
755779 }
756780 }
757781}
782+ impl < ' slf , ' s : ' slf > Unifier < ' slf , ' s , SecondType > for PeanoUnifier < ' s > {
783+ fn get_substitutor ( & ' slf self ) -> & ' slf Substitutor < ' s , SecondType , Self > {
784+ & self . second_subs
785+ }
786+ fn unify_subtrees ( & ' slf self , a : & ' s SecondType , b : & ' s SecondType ) -> UnifyResult {
787+ match ( a, b) {
788+ ( SecondType :: None , SecondType :: None ) => UnifyResult :: Success ,
789+ ( SecondType :: OnePeano ( a) , SecondType :: OnePeano ( b) ) => self . unify ( a, b) ,
790+ ( SecondType :: TwoPeano ( a1, a2) , SecondType :: TwoPeano ( b1, b2) ) => {
791+ self . unify ( a1, b1) & self . unify ( a2, b2)
792+ }
793+ _ => UnifyResult :: Failure ,
794+ }
795+ }
796+ fn set_subtrees ( & ' slf self , a : & ' s SecondType , b : SecondType ) -> UnifyResult {
797+ match ( a, b) {
798+ ( SecondType :: None , SecondType :: None ) => UnifyResult :: Success ,
799+ ( SecondType :: OnePeano ( a) , SecondType :: OnePeano ( b) ) => self . set_cell ( a, b) ,
800+ ( SecondType :: TwoPeano ( a1, a2) , SecondType :: TwoPeano ( b1, b2) ) => {
801+ self . set_cell ( a1, b1) & self . set_cell ( a2, b2)
802+ }
803+ _ => UnifyResult :: Failure ,
804+ }
805+ }
806+ fn contains_subtree ( & ' slf self , _in_obj : & SecondType , _subtree : SubTree < SecondType > ) -> bool {
807+ false // SecondType doesn't recurse
808+ }
809+ fn fully_substitute_recurse (
810+ & ' slf self ,
811+ known : & ' s SecondType ,
812+ ) -> Option < ResolveError < ' slf , ' s , Self > > {
813+ match known {
814+ SecondType :: None => None ,
815+ SecondType :: OnePeano ( a) => self . fully_substitute ( a) . err ( ) ,
816+ SecondType :: TwoPeano ( a, b) => {
817+ let a = self . fully_substitute ( a) . err ( ) ;
818+ let b = self . fully_substitute ( b) . err ( ) ;
819+ a. or ( b)
820+ }
821+ }
822+ }
823+ fn clone_known ( & ' slf self , known : & ' s SecondType ) -> SecondType {
824+ match known {
825+ SecondType :: None => SecondType :: None ,
826+ SecondType :: OnePeano ( a) => SecondType :: OnePeano ( self . clone_unify ( a) ) ,
827+ SecondType :: TwoPeano ( a, b) => {
828+ SecondType :: TwoPeano ( self . clone_unify ( a) , self . clone_unify ( b) )
829+ }
830+ }
831+ }
832+ }
758833
759834impl UniCell < PeanoType > {
760835 pub fn clone_prototype ( & self ) -> Self {
@@ -1180,6 +1255,40 @@ mod tests {
11801255 }
11811256 }
11821257
1258+ #[ test]
1259+ fn test_multi_substitutor ( ) {
1260+ let a = SecondType :: UNKNOWN ;
1261+ let b = SecondType :: UNKNOWN ;
1262+
1263+ let substitutor = PeanoUnifier :: new ( ) ;
1264+
1265+ substitutor
1266+ . set (
1267+ & a,
1268+ SecondType :: TwoPeano ( mk_peano_cell ( 1 ) , PeanoType :: UNKNOWN ) ,
1269+ )
1270+ . unwrap ( ) ;
1271+ substitutor
1272+ . set (
1273+ & b,
1274+ SecondType :: TwoPeano ( PeanoType :: UNKNOWN , mk_peano_cell ( 2 ) ) ,
1275+ )
1276+ . unwrap ( ) ;
1277+
1278+ substitutor. unify ( & a, & b) . unwrap ( ) ;
1279+
1280+ let a = substitutor. fully_substitute ( & a) . unwrap ( ) ;
1281+ let b = substitutor. fully_substitute ( & b) . unwrap ( ) ;
1282+
1283+ let_unwrap ! ( SecondType :: TwoPeano ( a1, a2) , a) ;
1284+ let_unwrap ! ( SecondType :: TwoPeano ( b1, b2) , b) ;
1285+
1286+ assert_eq ! ( a1. unwrap( ) . count( ) , 1 ) ;
1287+ assert_eq ! ( a2. unwrap( ) . count( ) , 2 ) ;
1288+ assert_eq ! ( b1. unwrap( ) . count( ) , 1 ) ;
1289+ assert_eq ! ( b2. unwrap( ) . count( ) , 2 ) ;
1290+ }
1291+
11831292 /// Just a stress test to cover all possible code paths. To check under miri that everything is alright.
11841293 #[ test]
11851294 fn stress_test_for_miri ( ) {
0 commit comments