Skip to content

Commit

Permalink
Auto merge of #767 - eggyal:rename-traits, r=jackh726
Browse files Browse the repository at this point in the history
Rename folding/visiting traits

Align the names of chalk's folding/visiting traits with those in rustc (especially once rust-lang/rust#98206) is merged.

r? `@jackh726`
  • Loading branch information
bors committed Jun 21, 2022
2 parents 48b1f1c + 23d39c9 commit ebdb87c
Show file tree
Hide file tree
Showing 40 changed files with 419 additions and 409 deletions.
2 changes: 1 addition & 1 deletion book/src/SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
- [Application types](./types/rust_types/application_ty.md)
- [Rust lifetimes](./types/rust_lifetimes.md)
- [Operations](./types/operations.md)
- [Fold and the Folder trait](./types/operations/fold.md)
- [TypeFoldable and the TypeFolder trait](./types/operations/fold.md)
- [Lowering Rust IR to logic](./clauses.md)
- [Goals and clauses](./clauses/goals_and_clauses.md)
- [Type equality and unification](./clauses/type_equality.md)
Expand Down
66 changes: 33 additions & 33 deletions book/src/types/operations/fold.md
Original file line number Diff line number Diff line change
@@ -1,64 +1,64 @@
# Fold and the Folder trait
# TypeFoldable and the TypeFolder trait

The [`Fold`] trait permits one to traverse a type or other term in the
The [`TypeFoldable`] trait permits one to traverse a type or other term in the
chalk-ir and make a copy of it, possibly making small substitutions or
alterations along the way. Folding also allows copying a term from one
interner to another.

[`Fold`]: https://rust-lang.github.io/chalk/chalk_ir/fold/trait.Fold.html
[`TypeFoldable`]: https://rust-lang.github.io/chalk/chalk_ir/fold/trait.TypeFoldable.html

To use the [`Fold`] trait, one invokes the [`Fold::fold_with`] method, supplying some
To use the [`TypeFoldable`] trait, one invokes the [`TypeFoldable::fold_with`] method, supplying some
"folder" as well as the number of "in scope binders" for that term (typically `0`
to start):

```rust,ignore
let output_ty = input_ty.fold_with(&mut folder, 0);
```

[`Fold::fold_with`]: https://rust-lang.github.io/chalk/chalk_ir/fold/trait.Fold.html#tymethod.fold_with
[`TypeFoldable::fold_with`]: https://rust-lang.github.io/chalk/chalk_ir/fold/trait.TypeFoldable.html#tymethod.fold_with

The folder is some instance of the [`Folder`] trait. This trait
The folder is some instance of the [`TypeFolder`] trait. This trait
defines a few key callbacks that allow you to substitute different
values as the fold proceeds. For example, when a type is folded, the
folder can substitute a new type in its place.

[`Folder`]: https://rust-lang.github.io/chalk/chalk_ir/fold/trait.Folder.html
[`TypeFolder`]: https://rust-lang.github.io/chalk/chalk_ir/fold/trait.TypeFolder.html

## Uses for folders

A common use for `Fold` is to permit a substitution -- that is,
A common use for `TypeFoldable` is to permit a substitution -- that is,
replacing generic type parameters with their values.

## From Fold to Folder to SuperFold and back again
## From TypeFoldable to TypeFolder to TypeSuperFoldable and back again

The overall flow of folding is like this.

1. [`Fold::fold_with`] is invoked on the outermost term. It recursively
1. [`TypeFoldable::fold_with`] is invoked on the outermost term. It recursively
walks the term.
2. For those sorts of terms (types, lifetimes, goals, program clauses) that have
callbacks in the [`Folder`] trait, invoking [`Fold::fold_with`] will in turn
invoke the corresponding method on the [`Folder`] trait, such as `Folder::fold_ty`.
3. The default implementation of `Folder::fold_ty`, in turn, invokes
`SuperFold::super_fold_with`. This will recursively fold the
callbacks in the [`TypeFolder`] trait, invoking [`TypeFoldable::fold_with`] will in turn
invoke the corresponding method on the [`TypeFolder`] trait, such as `TypeFolder::fold_ty`.
3. The default implementation of `TypeFolder::fold_ty`, in turn, invokes
`TypeSuperFoldable::super_fold_with`. This will recursively fold the
contents of the type. In some cases, the `super_fold_with`
implementation invokes more specialized methods on [`Folder`], such
as [`Folder::fold_free_var_ty`], which makes it easier to write
implementation invokes more specialized methods on [`TypeFolder`], such
as [`TypeFolder::fold_free_var_ty`], which makes it easier to write
folders that just intercept *certain* types.

[`Folder::fold_free_var_ty`]: https://rust-lang.github.io/chalk/chalk_ir/fold/trait.Folder.html#method.fold_free_var_ty
[`TypeFolder::fold_free_var_ty`]: https://rust-lang.github.io/chalk/chalk_ir/fold/trait.TypeFolder.html#method.fold_free_var_ty

Thus, as a user, you can customize folding by:

* Defining your own `Folder` type
* Defining your own `TypeFolder` type
* Implementing the appropriate methods to "intercept" types/lifetimes/etc at the right level of
detail
* In those methods, if you find a case where you would prefer not to
substitute a new value, then invoke `SuperFold::super_fold_with` to
substitute a new value, then invoke `TypeSuperFoldable::super_fold_with` to
return to the default behavior.

## The `binders` argument

Each callback in the [`Folder`] trait takes a `binders` argument. This indicates
Each callback in the [`TypeFolder`] trait takes a `binders` argument. This indicates
the number of binders that we have traversed during folding, which is relevant for De Bruijn indices.
So e.g. a bound variable with depth 1, if invoked with a `binders` value of 1, indicates something that was bound to something external to the fold.

Expand All @@ -70,32 +70,32 @@ Foo<'a>: for<'b> Bar<'b>

In this case, `Foo<'a>` gets visited with depth 0 and `Bar<'b>` gets visited with depth 1.

## The `Fold::Result` associated type
## The `TypeFoldable::Result` associated type

The `Fold` trait defines a [`Result`] associated type, indicating the
The `TypeFoldable` trait defines a [`Result`] associated type, indicating the
type that will result from folding.

[`Result`]: https://rust-lang.github.io/chalk/chalk_ir/fold/trait.Fold.html#associatedtype.Result
[`Result`]: https://rust-lang.github.io/chalk/chalk_ir/fold/trait.TypeFoldable.html#associatedtype.Result

## When to implement the Fold and SuperFold traits
## When to implement the TypeFoldable and TypeSuperFoldable traits

Any piece of IR that represents a kind of "term" (e.g., a type, part
of a type, or a goal, etc) in the logic should implement `Fold`. We
also implement `Fold` for common collection types like `Vec` as well
of a type, or a goal, etc) in the logic should implement `TypeFoldable`. We
also implement `TypeFoldable` for common collection types like `Vec` as well
as tuples, references, etc.

The `SuperFold` trait should only be implemented for those types that
have a callback defined on the `Folder` trait (e.g., types and
The `TypeSuperFoldable` trait should only be implemented for those types that
have a callback defined on the `TypeFolder` trait (e.g., types and
lifetimes).

## Derives

Using the `chalk-derive` crate, you can auto-derive the `Fold` trait.
There isn't presently a derive for `SuperFold` since it is very rare
to require it. The derive for `Fold` is a bit cludgy and requires:
Using the `chalk-derive` crate, you can auto-derive the `TypeFoldable` trait.
There isn't presently a derive for `TypeSuperFoldable` since it is very rare
to require it. The derive for `TypeFoldable` is a bit cludgy and requires:

* You must import `Fold` into scope.
* The type you are deriving `Fold` on must have either:
* You must import `TypeFoldable` into scope.
* The type you are deriving `TypeFoldable` on must have either:
* A type parameter that has a `Interner` bound, like `I: Interner`
* A type parameter that has a `HasInterner` bound, like `I: HasInterner`
* The `has_interner(XXX)` attribute.
Expand Down
22 changes: 11 additions & 11 deletions book/src/what_is_chalk/crates.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ The following crate is an implementation detail, used internally by `chalk-solve

* The `chalk-engine` crate, which defines the actual engine that solves logical predicate. This
engine is quite general and not really specific to Rust.
* The `chalk-derive` crate defines custom derives for the `chalk_ir::fold::Fold` trait and other
* The `chalk-derive` crate defines custom derives for the `chalk_ir::fold::TypeFoldable` trait and other
such things.

## Crates for standalone REPL and testing
Expand All @@ -37,11 +37,11 @@ define a kind of "minimal embedding" of chalk.

## The chalk-solve crate

| The `chalk-solve` crate | |
|---|--- |
| Purpose: | to solve a given goal |
| Depends on IR: | chalk-ir and rust-ir |
| Context required: | `RustIrDatabase` |
| The `chalk-solve` crate | |
| ----------------------- | --------------------- |
| Purpose: | to solve a given goal |
| Depends on IR: | chalk-ir and rust-ir |
| Context required: | `RustIrDatabase` |

The `chalk-solve` crate exposes a key type called `Solver`. This is a
solver that, given a goal (expressed in chalk-ir) will solve the goal
Expand All @@ -60,11 +60,11 @@ provide needed context for the solver -- notably, the solver can ask:

## The chalk-engine crate

| The `chalk-engine` crate | |
|---|--- |
| Purpose: | define the base solving strategy |
| IR: | none |
| Context required: | `Context` trait |
| The `chalk-engine` crate | |
| ------------------------ | -------------------------------- |
| Purpose: | define the base solving strategy |
| IR: | none |
| Context required: | `Context` trait |

For the purposes of chalk, the `chalk-engine` crate is effectively
encapsulated by `chalk-solve`. It defines the base SLG engine. It is
Expand Down
44 changes: 24 additions & 20 deletions chalk-derive/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -118,9 +118,9 @@ enum DeriveKind {
}

decl_derive!([HasInterner, attributes(has_interner)] => derive_has_interner);
decl_derive!([Visit, attributes(has_interner)] => derive_visit);
decl_derive!([SuperVisit, attributes(has_interner)] => derive_super_visit);
decl_derive!([Fold, attributes(has_interner)] => derive_fold);
decl_derive!([TypeVisitable, attributes(has_interner)] => derive_type_visitable);
decl_derive!([TypeSuperVisitable, attributes(has_interner)] => derive_type_super_visitable);
decl_derive!([TypeFoldable, attributes(has_interner)] => derive_type_foldable);
decl_derive!([Zip, attributes(has_interner)] => derive_zip);

fn derive_has_interner(mut s: synstructure::Structure) -> TokenStream {
Expand All @@ -136,24 +136,28 @@ fn derive_has_interner(mut s: synstructure::Structure) -> TokenStream {
)
}

/// Derives Visit for structs and enums for which one of the following is true:
/// Derives TypeVisitable for structs and enums for which one of the following is true:
/// - It has a `#[has_interner(TheInterner)]` attribute
/// - There is a single parameter `T: HasInterner` (does not have to be named `T`)
/// - There is a single parameter `I: Interner` (does not have to be named `I`)
fn derive_visit(s: synstructure::Structure) -> TokenStream {
derive_any_visit(s, parse_quote! { Visit }, parse_quote! { visit_with })
fn derive_type_visitable(s: synstructure::Structure) -> TokenStream {
derive_any_type_visitable(
s,
parse_quote! { TypeVisitable },
parse_quote! { visit_with },
)
}

/// Same as Visit, but derives SuperVisit instead
fn derive_super_visit(s: synstructure::Structure) -> TokenStream {
derive_any_visit(
/// Same as TypeVisitable, but derives TypeSuperVisitable instead
fn derive_type_super_visitable(s: synstructure::Structure) -> TokenStream {
derive_any_type_visitable(
s,
parse_quote! { SuperVisit },
parse_quote! { TypeSuperVisitable },
parse_quote! { super_visit_with },
)
}

fn derive_any_visit(
fn derive_any_type_visitable(
mut s: synstructure::Structure,
trait_name: Ident,
method_name: Ident,
Expand All @@ -164,13 +168,13 @@ fn derive_any_visit(

let body = s.each(|bi| {
quote! {
::chalk_ir::try_break!(::chalk_ir::visit::Visit::visit_with(#bi, visitor, outer_binder));
::chalk_ir::try_break!(::chalk_ir::visit::TypeVisitable::visit_with(#bi, visitor, outer_binder));
}
});

if kind == DeriveKind::FromHasInterner {
let param = get_generic_param_name(input).unwrap();
s.add_where_predicate(parse_quote! { #param: ::chalk_ir::visit::Visit<#interner> });
s.add_where_predicate(parse_quote! { #param: ::chalk_ir::visit::TypeVisitable<#interner> });
}

s.add_bounds(synstructure::AddBounds::None);
Expand All @@ -179,7 +183,7 @@ fn derive_any_visit(
quote! {
fn #method_name <B>(
&self,
visitor: &mut dyn ::chalk_ir::visit::Visitor < #interner, BreakTy = B >,
visitor: &mut dyn ::chalk_ir::visit::TypeVisitor < #interner, BreakTy = B >,
outer_binder: ::chalk_ir::DebruijnIndex,
) -> std::ops::ControlFlow<B> {
match *self {
Expand Down Expand Up @@ -250,11 +254,11 @@ fn derive_zip(mut s: synstructure::Structure) -> TokenStream {
)
}

/// Derives Fold for structs and enums for which one of the following is true:
/// Derives TypeFoldable for structs and enums for which one of the following is true:
/// - It has a `#[has_interner(TheInterner)]` attribute
/// - There is a single parameter `T: HasInterner` (does not have to be named `T`)
/// - There is a single parameter `I: Interner` (does not have to be named `I`)
fn derive_fold(mut s: synstructure::Structure) -> TokenStream {
fn derive_type_foldable(mut s: synstructure::Structure) -> TokenStream {
s.underscore_const(true);
s.bind_with(|_| synstructure::BindStyle::Move);

Expand All @@ -265,7 +269,7 @@ fn derive_fold(mut s: synstructure::Structure) -> TokenStream {
vi.construct(|_, index| {
let bind = &bindings[index];
quote! {
::chalk_ir::fold::Fold::fold_with(#bind, folder, outer_binder)?
::chalk_ir::fold::TypeFoldable::fold_with(#bind, folder, outer_binder)?
}
})
});
Expand All @@ -277,7 +281,7 @@ fn derive_fold(mut s: synstructure::Structure) -> TokenStream {
let param = get_generic_param_name(input).unwrap();
s.add_impl_generic(parse_quote! { _U })
.add_where_predicate(
parse_quote! { #param: ::chalk_ir::fold::Fold<#interner, Result = _U> },
parse_quote! { #param: ::chalk_ir::fold::TypeFoldable<#interner, Result = _U> },
)
.add_where_predicate(
parse_quote! { _U: ::chalk_ir::interner::HasInterner<Interner = #interner> },
Expand All @@ -289,13 +293,13 @@ fn derive_fold(mut s: synstructure::Structure) -> TokenStream {

s.add_bounds(synstructure::AddBounds::None);
s.bound_impl(
quote!(::chalk_ir::fold::Fold<#interner>),
quote!(::chalk_ir::fold::TypeFoldable<#interner>),
quote! {
type Result = #result;

fn fold_with<E>(
self,
folder: &mut dyn ::chalk_ir::fold::Folder < #interner, Error = E >,
folder: &mut dyn ::chalk_ir::fold::TypeFolder < #interner, Error = E >,
outer_binder: ::chalk_ir::DebruijnIndex,
) -> ::std::result::Result<Self::Result, E> {
Ok(match self { #body })
Expand Down
10 changes: 5 additions & 5 deletions chalk-engine/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@
use std::cmp::min;
use std::usize;

use chalk_derive::{Fold, HasInterner, Visit};
use chalk_derive::{HasInterner, TypeFoldable, TypeVisitable};
use chalk_ir::interner::Interner;
use chalk_ir::{
AnswerSubst, Canonical, ConstrainedSubst, Constraint, DebruijnIndex, Goal, InEnvironment,
Expand All @@ -78,13 +78,13 @@ mod table;
mod tables;

index_struct! {
pub struct TableIndex { // FIXME: pub b/c Fold
pub struct TableIndex { // FIXME: pub b/c TypeFoldable
value: usize,
}
}

/// The paper describes these as `A :- D | G`.
#[derive(Clone, Debug, PartialEq, Eq, Hash, Fold, Visit, HasInterner)]
#[derive(Clone, Debug, PartialEq, Eq, Hash, TypeFoldable, TypeVisitable, HasInterner)]
pub struct ExClause<I: Interner> {
/// The substitution which, applied to the goal of our table,
/// would yield A.
Expand Down Expand Up @@ -168,7 +168,7 @@ impl TimeStamp {
///
/// trying to solve `?T: Foo` would immediately require solving `?T:
/// Sized`, and hence would flounder.
#[derive(Clone, Debug, PartialEq, Eq, Hash, Fold, Visit)]
#[derive(Clone, Debug, PartialEq, Eq, Hash, TypeFoldable, TypeVisitable)]
pub struct FlounderedSubgoal<I: Interner> {
/// Literal that floundered.
pub floundered_literal: Literal<I>,
Expand Down Expand Up @@ -209,7 +209,7 @@ pub struct CompleteAnswer<I: Interner> {
}

/// Either `A` or `~A`, where `A` is a `Env |- Goal`.
#[derive(Clone, Debug, Fold, Visit)]
#[derive(Clone, Debug, TypeFoldable, TypeVisitable)]
pub enum Literal<I: Interner> {
// FIXME: pub b/c fold
Positive(InEnvironment<Goal<I>>),
Expand Down
8 changes: 4 additions & 4 deletions chalk-engine/src/normalize_deep.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use chalk_ir::fold::shift::Shift;
use chalk_ir::fold::{Fold, Folder};
use chalk_ir::fold::{TypeFoldable, TypeFolder};
use chalk_ir::interner::Interner;
use chalk_ir::*;
use chalk_solve::infer::InferenceTable;
Expand All @@ -21,7 +21,7 @@ impl<I: Interner> DeepNormalizer<'_, I> {
/// See also `InferenceTable::canonicalize`, which -- during real
/// processing -- is often used to capture the "current state" of
/// variables.
pub fn normalize_deep<T: Fold<I>>(
pub fn normalize_deep<T: TypeFoldable<I>>(
table: &mut InferenceTable<I>,
interner: I,
value: T,
Expand All @@ -35,10 +35,10 @@ impl<I: Interner> DeepNormalizer<'_, I> {
}
}

impl<I: Interner> Folder<I> for DeepNormalizer<'_, I> {
impl<I: Interner> TypeFolder<I> for DeepNormalizer<'_, I> {
type Error = NoSolution;

fn as_dyn(&mut self) -> &mut dyn Folder<I, Error = Self::Error> {
fn as_dyn(&mut self) -> &mut dyn TypeFolder<I, Error = Self::Error> {
self
}

Expand Down
4 changes: 2 additions & 2 deletions chalk-engine/src/slg/resolvent.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use crate::slg::ResolventOps;
use crate::{ExClause, Literal, TimeStamp};
use chalk_ir::cast::Caster;
use chalk_ir::fold::shift::Shift;
use chalk_ir::fold::Fold;
use chalk_ir::fold::TypeFoldable;
use chalk_ir::interner::{HasInterner, Interner};
use chalk_ir::zip::{Zip, Zipper};
use chalk_ir::*;
Expand Down Expand Up @@ -708,7 +708,7 @@ impl<'i, I: Interner> Zipper<I> for AnswerSubstitutor<'i, I> {
pending: &Binders<T>,
) -> Fallible<()>
where
T: HasInterner<Interner = I> + Zip<I> + Fold<I, Result = T>,
T: HasInterner<Interner = I> + Zip<I> + TypeFoldable<I, Result = T>,
{
self.outer_binder.shift_in();
Zip::zip_with(
Expand Down
Loading

0 comments on commit ebdb87c

Please sign in to comment.