---
# System prepended metadata

title: implied bounds in `predicates_of`

---

# implied bounds

Dealing with implied bounds has two parts: relying on them as assumptions and having to prove them as obligations.

Proving them should ideally just happen as part of `predicates_of` while relying on them should be simple.

### as requirements: `predicates_of`

Must not add implied bounds for closure signatures as that would cause query cycles when wf checking the closure during typeck of the parent:

* cannot make `predicates_of` for the closure include the implied bounds based on its arguments because it is used by the type check code, which infers the argument types

Function and closure signature is checked lazily anyways when calling the function or closure, so we can just not add them to `predicates_of` at all.

Add WF predicates for everything except functions and closures.

### as assumptions

Putting them in the `param_env` causes cycles for opaque types due to `Reveal::All` in const-eval queries.

can keep the current setup with `ocx.assumed_wf_types` for assumptions, not perfect, but good enough.

not really sure about borrowck yet. Borrowck has been solved :grin: 

## current issues

### placeholders in wf

fixed in https://github.com/rust-lang/rust/pull/103565

### new trait solver cycles

```rust
trait FromResidual<R> {}
trait Try: FromResidual<<Self as Try>::Residual> {
    type Residual;
}

struct Ready<T>(T);
impl<T> Try for Ready<T> {
    type Residual = Ready<()>;
}
impl<T> FromResidual<<Ready<T> as Try>::Residual> for Ready<T> {}
```

When checking that the impl of `FromResidual` is well formed we get the following cycle:

The impl is well formed if `<Ready<T> as Try>::Residual` and `Ready<T>` are well formed.

- `wf(<Ready<T> as Try>::Residual)` requires
-  `Ready<T>: Try`, which requires because of the super trait
-  `Ready<T>: FromResidual<Ready<T> as Try>::Residual>`, which has an impl which requires **because of implied bounds**
-  `wf(<Ready<T> as Try>::Residual)` :tada: **cycle**

The obligation `Ready<T>: Try` requiring us to prove the super traits is "at fault" here, not sure about how to deal with that. Alternatively, trait obligations should always be coinductive.

