Skip to content

Commit

Permalink
Merge pull request #78 from nikomatsakis/kill-eager-slg
Browse files Browse the repository at this point in the history
add answer abstraction to on-demand solver; remove eager SLG solver
  • Loading branch information
nikomatsakis authored Feb 6, 2018
2 parents b0d1417 + ac66730 commit 4defa33
Show file tree
Hide file tree
Showing 40 changed files with 1,091 additions and 3,295 deletions.
69 changes: 13 additions & 56 deletions src/bin/chalki.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ use std::process::exit;

use chalk::ir;
use chalk::lower::*;
use chalk::solve::slg;
use chalk::solve::SolverChoice;
use docopt::Docopt;
use rustyline::error::ReadlineError;
Expand All @@ -35,8 +34,7 @@ Options:
--program=PATH Specifies the path to the `.chalk` file containing traits/impls.
--goal=GOAL Specifies a goal to evaluate (may be given more than once).
--overflow-depth=N Specifies the overflow depth [default: 10].
--solver S Selects a solver (recursive, slg-eager, or slg-on-demand) [default: recursive]
--all-answers When using SLG solver, dump out each individual answer.
--solver S Selects a solver (recursive, slg) [default: recursive]
--no-cache Disable caching.
";

Expand All @@ -46,7 +44,6 @@ struct Args {
flag_goal: Vec<String>,
flag_overflow_depth: usize,
flag_solver: String,
flag_all_answers: bool,
flag_no_cache: bool,
}

Expand Down Expand Up @@ -90,24 +87,10 @@ fn run() -> Result<()> {

let mut prog = None;

let solver_choice = match args.solver_choice() {
Some(s) => s,
None => {
eprintln!("error: invalid solver choice `{}`", args.flag_solver);
eprintln!("try `recursive`, `slg-eager`, or `slg-on-demand`");
exit(1);
}
};

if args.flag_all_answers {
match solver_choice {
SolverChoice::SLG { eager: true, .. } => { }
_ => {
eprintln!("error: in order to report all answers, \
you must use the `slg-eager` solver");
exit(1);
}
}
if let None = args.solver_choice() {
eprintln!("error: invalid solver choice `{}`", args.flag_solver);
eprintln!("try `recursive` or `slg`");
exit(1);
}

if let Some(program) = &args.flag_program {
Expand Down Expand Up @@ -135,7 +118,7 @@ fn run() -> Result<()> {
}
};

ir::set_current_program(&prog.ir, || -> Result<()> {
ir::tls::set_current_program(&prog.ir, || -> Result<()> {
for g in &args.flag_goal {
if let Err(e) = goal(&args, g, &prog) {
eprintln!("error: {}", e);
Expand Down Expand Up @@ -185,7 +168,7 @@ fn process(
*prog = Some(load_program(args, filename)?);
} else {
let prog = prog.as_ref().ok_or("no program currently loaded")?;
ir::set_current_program(&prog.ir, || -> Result<()> {
ir::tls::set_current_program(&prog.ir, || -> Result<()> {
match command {
"print" => println!("{}", prog.text),
"lowered" => println!("{:#?}", prog.env),
Expand Down Expand Up @@ -228,45 +211,19 @@ fn read_program(rl: &mut rustyline::Editor<()>) -> Result<String> {
fn goal(args: &Args, text: &str, prog: &Program) -> Result<()> {
let goal = chalk_parse::parse_goal(text)?.lower(&*prog.ir)?;
let peeled_goal = goal.into_peeled_goal();
if args.flag_all_answers {
match slg::solve_root_goal(args.flag_overflow_depth, &prog.env, &peeled_goal) {
Ok(slg::SimplifiedAnswers { answers }) => if answers.is_empty() {
println!("No answers found.");
} else {
println!("{} answer(s) found:", answers.len());
for answer in &answers {
println!(
"- {}{}",
answer.subst,
if answer.ambiguous { " [ambiguous]" } else { "" }
);
}
},
Err(error) => {
println!("exploration error: {:?}\n", error);
}
}
} else {
let solver_choice = args.solver_choice().unwrap();
match solver_choice.solve_root_goal(&prog.env, &peeled_goal) {
Ok(Some(v)) => println!("{}\n", v),
Ok(None) => println!("No possible solution.\n"),
Err(e) => println!("Solver failed: {}", e),
}
let solver_choice = args.solver_choice().unwrap();
match solver_choice.solve_root_goal(&prog.env, &peeled_goal) {
Ok(Some(v)) => println!("{}\n", v),
Ok(None) => println!("No possible solution.\n"),
Err(e) => println!("Solver failed: {}", e),
}
Ok(())
}

impl Args {
fn solver_choice(&self) -> Option<SolverChoice> {
match &self.flag_solver[..] {
"slg-eager" => Some(SolverChoice::SLG {
eager: true,
max_size: self.flag_overflow_depth,
}),

"slg-on-demand" => Some(SolverChoice::SLG {
eager: false,
"slg" => Some(SolverChoice::SLG {
max_size: self.flag_overflow_depth,
}),

Expand Down
6 changes: 3 additions & 3 deletions src/cast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ use std::marker::PhantomData;
/// as part of this, they should always use the same set of free
/// variables (the `Canonical` implementation, for example, relies on
/// that).
pub trait Cast<T>: Sized {
crate trait Cast<T>: Sized {
fn cast(self) -> T;
}

Expand Down Expand Up @@ -232,7 +232,7 @@ where
}
}

pub struct Casted<I, U> {
crate struct Casted<I, U> {
iterator: I,
_cast: PhantomData<U>,
}
Expand All @@ -254,7 +254,7 @@ where

/// An iterator adapter that casts each element we are iterating over
/// to some other type.
pub trait Caster<U>: Sized {
crate trait Caster<U>: Sized {
fn casted(self) -> Casted<Self, U>;
}

Expand Down
4 changes: 2 additions & 2 deletions src/coherence/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ mod solve;


impl Program {
pub fn record_specialization_priorities(&mut self, solver_choice: SolverChoice) -> Result<()> {
ir::set_current_program(&Arc::new(self.clone()), || {
crate fn record_specialization_priorities(&mut self, solver_choice: SolverChoice) -> Result<()> {
ir::tls::set_current_program(&Arc::new(self.clone()), || {
let forest = self.build_specialization_forest(solver_choice)?;

// Visit every root in the forest & set specialization
Expand Down
22 changes: 11 additions & 11 deletions src/fold/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use std::sync::Arc;
crate mod shift;
mod subst;

pub use self::subst::Subst;
crate use self::subst::Subst;

/// A "folder" is a transformer that can be used to make a copy of
/// some term -- that is, some bit of IR, such as a `Goal` -- with
Expand Down Expand Up @@ -51,14 +51,14 @@ pub use self::subst::Subst;
/// ```rust,ignore
/// let x = x.fold_with(&mut folder, 0);
/// ```
pub trait Folder: ExistentialFolder + UniversalFolder + TypeFolder {
crate trait Folder: ExistentialFolder + UniversalFolder + TypeFolder {
/// Returns a "dynamic" version of this trait. There is no
/// **particular** reason to require this, except that I didn't
/// feel like making `super_fold_ty` generic for no reason.
fn to_dyn(&mut self) -> &mut Folder;
}

pub trait TypeFolder {
crate trait TypeFolder {
fn fold_ty(&mut self, ty: &Ty, binders: usize) -> Fallible<Ty>;
fn fold_lifetime(&mut self, lifetime: &Lifetime, binders: usize) -> Fallible<Lifetime>;
}
Expand All @@ -74,7 +74,7 @@ impl<T: ExistentialFolder + UniversalFolder + TypeFolder> Folder for T {
/// their contents (note that free variables that are encountered in
/// that process may still be substituted). The vast majority of
/// folders implement this trait.
pub trait DefaultTypeFolder {}
crate trait DefaultTypeFolder {}

impl<T: ExistentialFolder + UniversalFolder + DefaultTypeFolder> TypeFolder for T {
fn fold_ty(&mut self, ty: &Ty, binders: usize) -> Fallible<Ty> {
Expand All @@ -90,7 +90,7 @@ impl<T: ExistentialFolder + UniversalFolder + DefaultTypeFolder> TypeFolder for
/// variables**; for example, if you folded over `Foo<?T> }`, where `?T`
/// is an inference variable, then this would let you replace `?T` with
/// some other type.
pub trait ExistentialFolder {
crate trait ExistentialFolder {
/// Invoked for `Ty::Var` instances that are not bound within the type being folded
/// over:
///
Expand All @@ -112,7 +112,7 @@ pub trait ExistentialFolder {
/// A convenience trait. If you implement this, you get an
/// implementation of `UniversalFolder` for free that simply ignores
/// universal values (that is, it replaces them with themselves).
pub trait IdentityExistentialFolder {}
crate trait IdentityExistentialFolder {}

impl<T: IdentityExistentialFolder> ExistentialFolder for T {
fn fold_free_existential_ty(&mut self, depth: usize, binders: usize) -> Fallible<Ty> {
Expand All @@ -128,7 +128,7 @@ impl<T: IdentityExistentialFolder> ExistentialFolder for T {
}
}

pub trait UniversalFolder {
crate trait UniversalFolder {
/// Invoked for `Ty::Apply` instances where the type name is a `TypeName::ForAll`.
/// Returns a type to use instead, which should be suitably shifted to account for `binders`.
///
Expand All @@ -147,7 +147,7 @@ pub trait UniversalFolder {
/// A convenience trait. If you implement this, you get an
/// implementation of `UniversalFolder` for free that simply ignores
/// universal values (that is, it replaces them with themselves).
pub trait IdentityUniversalFolder {}
crate trait IdentityUniversalFolder {}

impl<T: IdentityUniversalFolder> UniversalFolder for T {
fn fold_free_universal_ty(&mut self, universe: UniverseIndex, _binders: usize) -> Fallible<Ty> {
Expand All @@ -164,7 +164,7 @@ impl<T: IdentityUniversalFolder> UniversalFolder for T {
}

/// Applies the given folder to a value.
pub trait Fold: Debug {
crate trait Fold: Debug {
/// The type of value that will be produced once folding is done.
/// Typically this is `Self`, unless `Self` contains borrowed
/// values, in which case owned values are produced (for example,
Expand Down Expand Up @@ -243,7 +243,7 @@ impl Fold for Ty {
}
}

pub fn super_fold_ty(folder: &mut Folder, ty: &Ty, binders: usize) -> Fallible<Ty> {
crate fn super_fold_ty(folder: &mut Folder, ty: &Ty, binders: usize) -> Fallible<Ty> {
match *ty {
Ty::Var(depth) => if depth >= binders {
folder.fold_free_existential_ty(depth - binders, binders)
Expand Down Expand Up @@ -337,7 +337,7 @@ impl Fold for Lifetime {
}
}

pub fn super_fold_lifetime(
crate fn super_fold_lifetime(
folder: &mut Folder,
lifetime: &Lifetime,
binders: usize,
Expand Down
2 changes: 1 addition & 1 deletion src/fold/shift.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use super::{DefaultTypeFolder, ExistentialFolder, Fold, IdentityUniversalFolder}

/// Methods for converting debruijn indices to move values into or out
/// of binders.
pub trait Shift: Fold {
crate trait Shift: Fold {
/// Shifts debruijn indices in `self` **up**, which is used when a
/// value is being placed under additional levels of binders.
///
Expand Down
10 changes: 3 additions & 7 deletions src/fold/subst.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,25 +3,21 @@ use ir::*;

use super::*;

pub struct Subst<'s> {
crate struct Subst<'s> {
/// Values to substitute. A reference to a free variable with
/// index `i` will be mapped to `parameters[i]` -- if `i >
/// parameters.len()`, then we will leave the variable untouched.
parameters: &'s [Parameter],
}

impl<'s> Subst<'s> {
pub fn new(parameters: &'s [Parameter]) -> Subst<'s> {
Subst { parameters }
}

pub fn apply<T: Fold>(parameters: &[Parameter], value: &T) -> T::Result {
crate fn apply<T: Fold>(parameters: &[Parameter], value: &T) -> T::Result {
value.fold_with(&mut Subst { parameters }, 0).unwrap()
}
}

impl QuantifiedTy {
pub fn substitute(&self, parameters: &[Parameter]) -> Ty {
crate fn substitute(&self, parameters: &[Parameter]) -> Ty {
assert_eq!(self.num_binders, parameters.len());
Subst::apply(parameters, &self.ty)
}
Expand Down
2 changes: 1 addition & 1 deletion src/ir/could_match.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use ir::*;
use zip::{Zip, Zipper};

/// A fast check to see whether two things could ever possibly match.
pub trait CouldMatch<T> {
crate trait CouldMatch<T> {
fn could_match(&self, other: &T) -> bool;
}

Expand Down
6 changes: 3 additions & 3 deletions src/ir/debug.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use super::*;

impl Debug for ItemId {
fn fmt(&self, fmt: &mut Formatter) -> Result<(), Error> {
with_current_program(|p| match p {
tls::with_current_program(|p| match p {
Some(prog) => if let Some(k) = prog.type_kinds.get(self) {
write!(fmt, "{}", k.name)
} else if let Some(k) = prog.associated_ty_data.get(self) {
Expand Down Expand Up @@ -95,7 +95,7 @@ impl Debug for TraitRef {

impl Debug for ProjectionTy {
fn fmt(&self, fmt: &mut Formatter) -> Result<(), Error> {
with_current_program(|p| match p {
tls::with_current_program(|p| match p {
Some(program) => {
let (associated_ty_data, trait_params, other_params) =
program.split_projection(self);
Expand Down Expand Up @@ -131,7 +131,7 @@ impl Debug for UnselectedProjectionTy {
}
}

pub struct Angle<'a, T: 'a>(pub &'a [T]);
crate struct Angle<'a, T: 'a>(pub &'a [T]);

impl<'a, T: Debug> Debug for Angle<'a, T> {
fn fmt(&self, fmt: &mut Formatter) -> Result<(), Error> {
Expand Down
Loading

0 comments on commit 4defa33

Please sign in to comment.