Skip to content

Commit f6da755

Browse files
committed
encapsulate the coinductive logic into chalk-solve
This also removes the need to work around the lack of trait object upcasts.
1 parent 97a7b60 commit f6da755

File tree

7 files changed

+54
-72
lines changed

7 files changed

+54
-72
lines changed

chalk-ir/src/lib.rs

Lines changed: 0 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -53,14 +53,6 @@ pub mod tls;
5353

5454
pub type Identifier = InternedString;
5555

56-
pub trait IsCoinductive {
57-
/// Convert to a dyn trait value representing `self`. This is a
58-
/// workaround for the lack of proper upcasting in Rust.
59-
fn as_dyn(&self) -> &dyn IsCoinductive;
60-
61-
fn is_coinductive_trait(&self, trait_id: TraitId) -> bool;
62-
}
63-
6456
#[derive(Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
6557
/// The set of assumptions we've made so far, and the current number of
6658
/// universal (forall) quantifiers we're within.
@@ -925,16 +917,6 @@ impl<T> UCanonical<T> {
925917
}
926918
}
927919

928-
impl UCanonical<InEnvironment<Goal>> {
929-
/// A goal has coinductive semantics if it is of the form `T: AutoTrait`, or if it is of the
930-
/// form `WellFormed(T: Trait)` where `Trait` is any trait. The latter is needed for dealing
931-
/// with WF requirements and cyclic traits, which generates cycles in the proof tree which must
932-
/// not be rejected but instead must be treated as a success.
933-
pub fn is_coinductive(&self, program: &dyn IsCoinductive) -> bool {
934-
self.canonical.value.goal.is_coinductive(program)
935-
}
936-
}
937-
938920
#[derive(Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
939921
/// A general goal; this is the full range of questions you can pose to Chalk.
940922
pub enum Goal {
@@ -999,18 +981,6 @@ impl Goal {
999981
pub fn implied_by(self, predicates: Vec<ProgramClause>) -> Goal {
1000982
Goal::Implies(predicates, Box::new(self))
1001983
}
1002-
1003-
pub fn is_coinductive(&self, program: &dyn IsCoinductive) -> bool {
1004-
match self {
1005-
Goal::Leaf(LeafGoal::DomainGoal(DomainGoal::Holds(wca))) => match wca {
1006-
WhereClause::Implemented(tr) => program.is_coinductive_trait(tr.trait_id),
1007-
WhereClause::ProjectionEq(..) => false,
1008-
},
1009-
Goal::Leaf(LeafGoal::DomainGoal(DomainGoal::WellFormed(WellFormed::Trait(..)))) => true,
1010-
Goal::Quantified(QuantifierKind::ForAll, goal) => goal.value.is_coinductive(program),
1011-
_ => false,
1012-
}
1013-
}
1014984
}
1015985

1016986
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]

chalk-rules/src/lib.rs

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,6 @@ pub trait GoalSolver {
1919
}
2020

2121
pub trait RustIrSource {
22-
/// Convert to a dyn trait value representing `self`. This is a
23-
/// workaround for the lack of proper upcasting in Rust.
24-
fn as_dyn(&self) -> &dyn RustIrSource;
25-
2622
/// Returns the datum for the associated type with the given id.
2723
fn associated_ty_data(&self, ty: TypeId) -> Arc<AssociatedTyDatum>;
2824

chalk-solve/src/coinductive_goal.rs

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
use crate::ChalkSolveDatabase;
2+
use chalk_ir::*;
3+
4+
pub trait IsCoinductive {
5+
/// A goal G has coinductive semantics if proving G is allowed to
6+
/// assume G is true (very roughly speaking). In the case of
7+
/// chalk-ir, this is true for goals of the form `T: AutoTrait`,
8+
/// or if it is of the form `WellFormed(T: Trait)` where `Trait`
9+
/// is any trait. The latter is needed for dealing with WF
10+
/// requirements and cyclic traits, which generates cycles in the
11+
/// proof tree which must not be rejected but instead must be
12+
/// treated as a success.
13+
fn is_coinductive(&self, db: &dyn ChalkSolveDatabase) -> bool;
14+
}
15+
16+
impl IsCoinductive for Goal {
17+
fn is_coinductive(&self, db: &dyn ChalkSolveDatabase) -> bool {
18+
match self {
19+
Goal::Leaf(LeafGoal::DomainGoal(DomainGoal::Holds(wca))) => match wca {
20+
WhereClause::Implemented(tr) => db.is_coinductive_trait(tr.trait_id),
21+
WhereClause::ProjectionEq(..) => false,
22+
},
23+
Goal::Leaf(LeafGoal::DomainGoal(DomainGoal::WellFormed(WellFormed::Trait(..)))) => true,
24+
Goal::Quantified(QuantifierKind::ForAll, goal) => goal.value.is_coinductive(db),
25+
_ => false,
26+
}
27+
}
28+
}
29+
30+
impl IsCoinductive for UCanonical<InEnvironment<Goal>> {
31+
fn is_coinductive(&self, db: &dyn ChalkSolveDatabase) -> bool {
32+
self.canonical.value.goal.is_coinductive(db)
33+
}
34+
}

chalk-solve/src/lib.rs

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,26 @@
1+
use chalk_ir::{DomainGoal, ProgramClause, TraitId};
2+
use std::fmt::Debug;
3+
14
#[macro_use]
25
extern crate chalk_macros;
3-
extern crate chalk_engine;
4-
extern crate chalk_ir;
56

7+
mod coinductive_goal;
68
pub mod ext;
79
mod infer;
810
mod solve;
911

10-
pub use solve::ChalkSolveDatabase;
12+
/// The trait for defining the program clauses that are in scope when
13+
/// solving a goal.
14+
pub trait ChalkSolveDatabase: Debug {
15+
/// Returns a set of program clauses that could possibly match
16+
/// `goal`. This can be any superset of the correct set, but the
17+
/// more precise you can make it, the more efficient solving will
18+
/// be.
19+
fn program_clauses_that_could_match(&self, goal: &DomainGoal, vec: &mut Vec<ProgramClause>);
20+
21+
fn is_coinductive_trait(&self, trait_id: TraitId) -> bool;
22+
}
23+
1124
pub use solve::Solution;
1225
pub use solve::Solver;
1326
pub use solve::SolverChoice;

chalk-solve/src/solve.rs

Lines changed: 1 addition & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,8 @@
11
use crate::solve::slg::SlgContext;
2+
use crate::ChalkSolveDatabase;
23
use chalk_engine::forest::Forest;
3-
use chalk_ir::DomainGoal;
4-
use chalk_ir::IsCoinductive;
5-
use chalk_ir::ProgramClause;
64
use chalk_ir::*;
75
use std::fmt;
8-
use std::fmt::Debug;
96

107
mod slg;
118
mod truncate;
@@ -187,17 +184,3 @@ impl TestSolver {
187184
self.forest.num_cached_answers_for_goal(&ops, goal)
188185
}
189186
}
190-
191-
/// The trait for defining the program clauses that are in scope when
192-
/// solving a goal.
193-
pub trait ChalkSolveDatabase: Debug + IsCoinductive {
194-
/// Convert to a dyn trait value representing `self`. This is a
195-
/// workaround for the lack of proper upcasting in Rust.
196-
fn as_dyn(&self) -> &dyn ChalkSolveDatabase;
197-
198-
/// Returns a set of program clauses that could possibly match
199-
/// `goal`. This can be any superset of the correct set, but the
200-
/// more precise you can make it, the more efficient solving will
201-
/// be.
202-
fn program_clauses_that_could_match(&self, goal: &DomainGoal, vec: &mut Vec<ProgramClause>);
203-
}

chalk-solve/src/solve/slg.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
1+
use crate::coinductive_goal::IsCoinductive;
12
use crate::infer::ucanonicalize::{UCanonicalized, UniverseMap};
23
use crate::infer::unify::UnificationResult;
34
use crate::infer::InferenceTable;
45
use crate::solve::truncate::{self, Truncated};
5-
use crate::solve::ChalkSolveDatabase;
66
use crate::solve::Solution;
7+
use crate::ChalkSolveDatabase;
78
use chalk_engine::fallible::Fallible;
89
use chalk_ir::cast::{Cast, Caster};
910
use chalk_ir::could_match::CouldMatch;
@@ -120,7 +121,7 @@ impl context::Context for SlgContext {
120121

121122
impl<'me> context::ContextOps<SlgContext> for SlgContextOps<'me> {
122123
fn is_coinductive(&self, goal: &UCanonical<InEnvironment<Goal>>) -> bool {
123-
goal.is_coinductive(IsCoinductive::as_dyn(self.program))
124+
goal.is_coinductive(self.program)
124125
}
125126

126127
fn instantiate_ucanonical_goal<R>(

src/db.rs

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ use chalk_ir::Goal;
99
use chalk_ir::Identifier;
1010
use chalk_ir::ImplId;
1111
use chalk_ir::InEnvironment;
12-
use chalk_ir::IsCoinductive;
1312
use chalk_ir::Parameter;
1413
use chalk_ir::ProgramClause;
1514
use chalk_ir::ProjectionTy;
@@ -65,10 +64,6 @@ impl ChalkDatabase {
6564
}
6665

6766
impl ChalkSolveDatabase for ChalkDatabase {
68-
fn as_dyn(&self) -> &dyn ChalkSolveDatabase {
69-
self
70-
}
71-
7267
fn program_clauses_that_could_match(&self, goal: &DomainGoal, vec: &mut Vec<ProgramClause>) {
7368
if let Ok(env) = self.environment() {
7469
vec.extend(
@@ -79,12 +74,6 @@ impl ChalkSolveDatabase for ChalkDatabase {
7974
);
8075
}
8176
}
82-
}
83-
84-
impl IsCoinductive for ChalkDatabase {
85-
fn as_dyn(&self) -> &dyn IsCoinductive {
86-
self
87-
}
8877

8978
fn is_coinductive_trait(&self, trait_id: TraitId) -> bool {
9079
if let Ok(env) = self.environment() {
@@ -96,10 +85,6 @@ impl IsCoinductive for ChalkDatabase {
9685
}
9786

9887
impl RustIrSource for ChalkDatabase {
99-
fn as_dyn(&self) -> &dyn RustIrSource {
100-
self
101-
}
102-
10388
fn associated_ty_data(&self, ty: TypeId) -> Arc<AssociatedTyDatum> {
10489
self.program_ir().unwrap().associated_ty_data[&ty].clone()
10590
}

0 commit comments

Comments
 (0)