1- /// Multi-sorted CHC system with tuples.
1+ //! A multi-sorted CHC system with tuples.
2+
23use pretty:: { termcolor, Pretty } ;
34use rustc_index:: IndexVec ;
45
@@ -17,6 +18,7 @@ pub use debug::DebugInfo;
1718pub use solver:: { CheckSatError , Config } ;
1819pub use unbox:: unbox;
1920
21+ /// A name of a datatype.
2022#[ derive( Debug , Clone , PartialEq , Eq , Hash , PartialOrd , Ord ) ]
2123pub struct DatatypeSymbol {
2224 inner : String ,
@@ -43,6 +45,10 @@ impl DatatypeSymbol {
4345 }
4446}
4547
48+ /// A datatype sort.
49+ ///
50+ /// A datatype sort is a sort that is defined by a datatype. It has a symbol and a list of
51+ /// argument sorts.
4652#[ derive( Debug , Clone , PartialEq , Eq , Hash , PartialOrd , Ord ) ]
4753pub struct DatatypeSort {
4854 symbol : DatatypeSymbol ,
@@ -74,6 +80,7 @@ impl DatatypeSort {
7480 }
7581}
7682
83+ /// A sort is the type of a logical term.
7784#[ derive( Debug , Clone , PartialEq , Eq , Hash , PartialOrd , Ord ) ]
7885pub enum Sort {
7986 Null ,
@@ -271,6 +278,10 @@ impl Sort {
271278}
272279
273280rustc_index:: newtype_index! {
281+ /// An index representing term-level variable.
282+ ///
283+ /// We manage term-level variables using indices that are unique in each clause.
284+ /// [`Clause`] contains `IndexVec<TermVarIdx, Sort>` that manages the indices and the sorts of the variables.
274285 #[ orderable]
275286 #[ debug_format = "v{}" ]
276287 pub struct TermVarIdx { }
@@ -297,6 +308,7 @@ impl TermVarIdx {
297308 }
298309}
299310
311+ /// A known function symbol.
300312#[ derive( Debug , Clone , Copy , PartialEq , Eq , Hash ) ]
301313pub struct Function {
302314 name : & ' static str ,
@@ -376,6 +388,7 @@ impl Function {
376388 pub const NEG : Function = Function :: new ( "-" ) ;
377389}
378390
391+ /// A logical term.
379392#[ derive( Debug , Clone ) ]
380393pub enum Term < V = TermVarIdx > {
381394 Null ,
@@ -693,6 +706,11 @@ impl<V> Term<V> {
693706}
694707
695708rustc_index:: newtype_index! {
709+ /// An index representing predicate variables.
710+ ///
711+ /// We manage predicate variables using indices that are unique in a CHC system.
712+ /// [`System`] contains `IndexVec<PredVarId, PredVarDef>` that manages the indices
713+ /// and signatures of the predicate variables.
696714 #[ debug_format = "p{}" ]
697715 pub struct PredVarId { }
698716}
@@ -720,6 +738,9 @@ impl PredVarId {
720738 }
721739}
722740
741+ /// A known predicate.
742+ ///
743+ /// A known predicate is a predicate that has a fixed meaning, such as `true`, `false`, `=`, etc.
723744#[ derive( Debug , Clone , Copy , PartialEq , Eq , Hash ) ]
724745pub struct KnownPred {
725746 name : & ' static str ,
@@ -804,6 +825,25 @@ impl KnownPred {
804825 pub const GREATER_THAN : KnownPred = KnownPred :: infix ( ">" ) ;
805826}
806827
828+ /// A matcher predicate.
829+ ///
830+ /// A matcher predicate is a predicate that relates a value of a datatype with its contents.
831+ /// For example, given the following `enum` datatype:
832+ ///
833+ /// ```rust
834+ /// pub enum X {
835+ /// A(i64),
836+ /// B(bool),
837+ /// }
838+ /// ```
839+ ///
840+ /// The corresponding matcher predicate is defined as:
841+ ///
842+ /// ```smtlib2
843+ /// (define-fun matcher_pred<X> ((x0 Int) (x1 Bool) (v X)) Bool (or (= v (X.A x0)) (= v (X.B x1))))
844+ /// ```
845+ ///
846+ /// See the implementation in the [`smtlib2`] module for the details.
807847#[ derive( Debug , Clone , PartialEq , Eq , Hash ) ]
808848pub struct MatcherPred {
809849 datatype_symbol : DatatypeSymbol ,
@@ -851,6 +891,7 @@ impl MatcherPred {
851891 }
852892}
853893
894+ /// A predicate.
854895#[ derive( Debug , Clone , PartialEq , Eq , Hash ) ]
855896pub enum Pred {
856897 Known ( KnownPred ) ,
@@ -942,6 +983,7 @@ impl Pred {
942983 }
943984}
944985
986+ /// An atom is a predicate applied to a list of terms.
945987#[ derive( Debug , Clone ) ]
946988pub struct Atom < V = TermVarIdx > {
947989 pub pred : Pred ,
@@ -1030,6 +1072,11 @@ impl<V> Atom<V> {
10301072 }
10311073}
10321074
1075+ /// An arbitrary formula built with atoms and logical connectives.
1076+ ///
1077+ /// While it allows arbitrary [`Atom`] in its `Atom` variant, we only expect atoms with known
1078+ /// predicates (i.e., predicates other than `Pred::Var`) to appear in formulas. It is our TODO to
1079+ /// enforce this restriction statically. Also see the definition of [`Body`].
10331080#[ derive( Debug , Clone ) ]
10341081pub enum Formula < V = TermVarIdx > {
10351082 Atom ( Atom < V > ) ,
@@ -1248,10 +1295,11 @@ impl<V> Formula<V> {
12481295 }
12491296}
12501297
1298+ /// The body part of a clause, consisting of atoms and a formula.
12511299#[ derive( Debug , Clone ) ]
12521300pub struct Body < V = TermVarIdx > {
12531301 pub atoms : Vec < Atom < V > > ,
1254- // `formula` doesn't contain PredVar
1302+ /// NOTE: This doesn't contain predicate variables. Also see [`Formula`].
12551303 pub formula : Formula < V > ,
12561304}
12571305
@@ -1391,6 +1439,10 @@ where
13911439 }
13921440}
13931441
1442+ /// A constrained Horn clause.
1443+ ///
1444+ /// A constrained Horn clause is a formula of the form `∀vars. body ⇒ head` where `body` is a conjunction of
1445+ /// atoms and underlying logical formula, and `head` is an atom.
13941446#[ derive( Debug , Clone ) ]
13951447pub struct Clause {
13961448 pub vars : IndexVec < TermVarIdx , Sort > ,
@@ -1441,19 +1493,26 @@ impl Clause {
14411493 }
14421494}
14431495
1496+ /// A selector for a datatype constructor.
1497+ ///
1498+ /// A selector is a function that extracts a field from a datatype value.
1499+ /// Through currently we don't use selectors to access datatype fields in [`Term`]s,
1500+ /// we require the symbol as selector name to emit SMT-LIB2 representation of datatypes.
14441501#[ derive( Debug , Clone ) ]
14451502pub struct DatatypeSelector {
14461503 pub symbol : DatatypeSymbol ,
14471504 pub sort : Sort ,
14481505}
14491506
1507+ /// A datatype constructor.
14501508#[ derive( Debug , Clone ) ]
14511509pub struct DatatypeCtor {
14521510 pub symbol : DatatypeSymbol ,
14531511 pub selectors : Vec < DatatypeSelector > ,
14541512 pub discriminant : u32 ,
14551513}
14561514
1515+ /// A datatype definition.
14571516#[ derive( Debug , Clone ) ]
14581517pub struct Datatype {
14591518 pub symbol : DatatypeSymbol ,
@@ -1462,18 +1521,25 @@ pub struct Datatype {
14621521}
14631522
14641523rustc_index:: newtype_index! {
1524+ /// An index of [`Clause`].
1525+ ///
1526+ /// [`System`] contains `IndexVec<ClauseId, Clause>` that manages the indices and the clauses.
14651527 #[ debug_format = "c{}" ]
14661528 pub struct ClauseId { }
14671529}
14681530
14691531pub type PredSig = Vec < Sort > ;
14701532
1533+ /// A predicate variable definition.
14711534#[ derive( Debug , Clone ) ]
14721535pub struct PredVarDef {
14731536 pub sig : PredSig ,
1537+ /// We may attach a debug information to include in the resulting SMT-LIB2 file to indicate the
1538+ /// origin of predicate variables.
14741539 pub debug_info : DebugInfo ,
14751540}
14761541
1542+ /// A CHC system.
14771543#[ derive( Debug , Clone , Default ) ]
14781544pub struct System {
14791545 pub datatypes : Vec < Datatype > ,
@@ -1498,6 +1564,13 @@ impl System {
14981564 smtlib2:: System :: new ( self )
14991565 }
15001566
1567+ /// Solves the CHC using an external SMT solver.
1568+ ///
1569+ /// This method first performs some optimization of the CHC,
1570+ /// then formats it to SMT-LIB2, and finally calls the configured CHC solver.
1571+ /// The solver and its arguments can be configured using environment
1572+ /// variables
1573+ /// (see <https://github.com/coord-e/thrust?tab=readme-ov-file#configuration>).
15011574 pub fn solve ( & self ) -> Result < ( ) , CheckSatError > {
15021575 let system = unbox ( self . clone ( ) ) ;
15031576 if let Ok ( file) = std:: env:: var ( "THRUST_PRETTY_OUTPUT" ) {
0 commit comments