Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
13 changes: 13 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,21 @@ 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 alternative "spellings" that it is equivalent to.
Copy link
Contributor

Choose a reason for hiding this comment

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

do we use "spellings" somewhere else? 🤔 would otherwise like to avoid even more terminology here '^^

We do use "underlying type" in rustc I think. i don't remember whether we'e talked about that before, but I feel like maybe we should change prove_normalize to take an alias type and limit the candidate to only x which are aliases

Copy link
Member Author

Choose a reason for hiding this comment

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

👍 i changed the wording

and yeah we have an issue open for that #201, i planned to get to that soon.

// 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`).
(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