Skip to content

Commit c2549a2

Browse files
committed
document why the changes to is_coinductive are ok
1 parent bfb5144 commit c2549a2

File tree

1 file changed

+33
-1
lines changed

1 file changed

+33
-1
lines changed

chalk-solve/src/coinductive_goal.rs

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,18 @@ pub trait IsCoinductive<I: Interner> {
1515
}
1616

1717
impl<I: Interner> IsCoinductive<I> for Goal<I> {
18+
/// A "coinductive" goal `G` is a goal where `G :- G` should be considered
19+
/// true. When we are doing trait solving, if we encounter a cycle of goals
20+
/// where solving `G1` requires `G2..Gn` and solving `Gn` requires `G1`,
21+
/// then our behavior depends on whether each goal `Gi` in that cycle is
22+
/// coinductive.
23+
///
24+
/// If all the goals are coinductive, then `G1` is considered provable,
25+
/// presuming that all the other subgoals for `G2..Gn` within can be fully
26+
/// proven.
27+
///
28+
/// If any goal `Gi` in the cycle is inductive, however, then the cycle is
29+
/// considered unprovable.
1830
fn is_coinductive(&self, db: &dyn RustIrDatabase<I>) -> bool {
1931
let interner = db.interner();
2032
match self.data(interner) {
@@ -27,9 +39,29 @@ impl<I: Interner> IsCoinductive<I> for Goal<I> {
2739
},
2840
GoalData::DomainGoal(DomainGoal::WellFormed(WellFormed::Trait(..))) => true,
2941
GoalData::DomainGoal(_) => false,
42+
43+
// Goals like `forall<..> { G }` or `... => G` we will consider to
44+
// be coinductive if G is coinductive, although in practice I think
45+
// it would be ok to simply consider them coinductive all the time.
3046
GoalData::Quantified(_, goal) => goal.skip_binders().is_coinductive(db),
31-
GoalData::All(..) => true,
3247
GoalData::Implies(_, goal) => goal.is_coinductive(db),
48+
49+
// The "All(...)" quantifier is considered coinductive. This could
50+
// be somewhat surprising as you might have `All(Gc, Gi)` where `Gc`
51+
// is coinductive and `Gi` is inductive. This however is really no
52+
// different than defining a fresh coinductive goal like
53+
//
54+
// ```notrust
55+
// Gx :- Gc, Gi
56+
// ```
57+
//
58+
// and requiring `Gx` in place of `All(Gc, Gi)`, and that would be
59+
// perfectly reasonable.
60+
GoalData::All(..) => true,
61+
62+
// For simplicity, just assume these remaining types of goals must
63+
// be inductive, since there is no pressing reason to consider them
64+
// coinductive.
3365
GoalData::Not(_) => false,
3466
GoalData::EqGoal(_) => false,
3567
GoalData::CannotProve(_) => false,

0 commit comments

Comments
 (0)