Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 43 additions & 0 deletions crates/formality-check/src/impls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,46 @@ impl super::Check<'_> {
}
}

/// Check that function `ii_fn` that appears in an impl is valid.
/// This includes the core check from [`Self::check_fn`],
/// but also additional checks to ensure that the signature in the impl
/// matches what is declared in the trait.
///
/// # Example
///
/// Suppose we are checking `<Cup<L> as Potable>::drink` in this example...
///
/// ```rust,ignore
/// trait Potable {
/// fn drink(&self) // `trait_items` includes both fn drink and fn smell
/// where Self: Copy; // <-- ti_where_clauses
/// fn smell(&self);
/// }
///
/// struct Water;
/// impl Potable for Water {
/// fn drink(&self) {}
/// fn smell(&self) {}
/// }
///
/// struct Cup<L>;
/// impl<L> Potable for Cup<L> // <-- env has `L` in scope
/// where
/// L: Potable, // <-- `impl_assumptions`
/// {
/// fn drink(&self) {} // <-- `ii_fn`
/// where (Cup<L>,): Copy; // <-- ii_where_clauses, implied by ti_where_clauses, Cup<L>: Copy, ok
/// fn smell(&self) {} // not currently being checked
/// }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this example is not fully general. I think another important part is that the instantiated trait method where-clauses imply the impl method where-clauses

/// ```
///
/// # Parameters
///
/// * `env`, the environment from the impl header
/// * `impl_assumptions`, where-clauses declared on the impl
/// * `trait_items`, items declared in the trait that is being implemented
/// (we search this to find the corresponding declaration of the method)
/// * `ii_fn`, the fn as declared in the impl
fn check_fn_in_impl(
&self,
env: &Env,
Expand Down Expand Up @@ -149,12 +189,14 @@ impl super::Check<'_> {

let mut env = env.clone();
let (
// ii_: the signature of the function as found in the impl item (ii)
FnBoundData {
input_tys: ii_input_tys,
output_ty: ii_output_ty,
where_clauses: ii_where_clauses,
body: _,
},
// ti_: the signature of the function as found in the trait item (ti)
FnBoundData {
input_tys: ti_input_tys,
output_ty: ti_output_ty,
Expand All @@ -169,6 +211,7 @@ impl super::Check<'_> {
&ii_where_clauses,
)?;

// Must have same number of arguments as declared in the trait
if ii_input_tys.len() != ti_input_tys.len() {
bail!(
"impl has {} function arguments but trait has {} function arguments",
Expand Down
12 changes: 12 additions & 0 deletions crates/formality-prove/src/prove/prove_eq.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,20 @@ judgment_fn! {
(prove_eq(decls, env, assumptions, Variable::ExistentialVar(v), r) => c)
)

// Example: we are trying to prove `x` (which equals `<SomeX<?V> as Iterator>::Item`)
// is equal to some type `z`.
(
// Normalize `x` will find its underlying type along with its constraints.
// For example, if there is an impl like `impl Iterator for SomeX<i32> { type Item = u32; ... }`
// then `prove_normalize` would yield `(c, u32)` where `c` are any constraints
// needed to show that it normalized (in this case, `c` would include the
// substitution `?V = i32`) to u32.
(prove_normalize(&decls, env, &assumptions, &x) => (c, y))

// Now that we know that `x` is equivalent to `y`, we try to prove
// that `y` is equivalent to `z` (our original goal).
// We do that with `prove_after` so that the constraints `c` are considered
// (e.g., if `z` includes `?V`, it will be replaced with `i32`).
(prove_after(&decls, c, &assumptions, eq(y, &z)) => c)
----------------------------- ("normalize-l")
(prove_eq(decls, env, assumptions, x, z) => c)
Expand Down
6 changes: 6 additions & 0 deletions crates/formality-types/src/grammar/wc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,12 @@ pub enum WcData {
#[grammar(for $v0)]
ForAll(Binder<Wc>),

// An *implication* `if $v0 $v1` says "assuming v0 is true, v1 is true".
// These are useful to express hypothetical syntax like
// `for<'a: 'b, 'b>` or as part of an implied bounds scheme
// where you might make the Rust syntax `for<'a, 'b> T: Something<'a, 'b>`
// expand to `for<'a, 'b> if ('a: 'b) (T: Something<'a, 'b>)`
// (given `trait Something<'a, 'b> where 'a: 'b`).
#[grammar(if $v0 $v1)]
Implies(Wcs, Wc),
}
Expand Down