Auto merge of #89970 - jackh726:gats_diagnostics, r=nikomatsakis
Implementation of GATs outlives lint See #87479 for background. Closes #87479 The basic premise of this lint/error is to require the user to write where clauses on a GAT when those bounds can be implied or proven from any function on the trait returning that GAT. ## Intuitive Explanation (Attempt) ## Let's take this trait definition as an example: ```rust trait Iterable { type Item<'x>; fn iter<'a>(&'a self) -> Self::Item<'a>; } ``` Let's focus on the `iter` function. The first thing to realize is that we know that `Self: 'a` because of `&'a self`. If an impl wants `Self::Item` to contain any data with references, then those references must be derived from `&'a self`. Thus, they must live only as long as `'a`. Furthermore, because of the `Self: 'a` implied bound, they must live only as long as `Self`. Since it's `'a` is used in place of `'x`, it is reasonable to assume that any value of `Self::Item<'x>`, and thus `'x`, will only be able to live as long as `Self`. Therefore, we require this bound on `Item` in the trait. As another example: ```rust trait Deserializer<T> { type Out<'x>; fn deserialize<'a>(&self, input: &'a T) -> Self::Out<'a>; } ``` The intuition is similar here, except rather than a `Self: 'a` implied bound, we have a `T: 'a` implied bound. Thus, the data on `Self::Out<'a>` is derived from `&'a T`, and thus it is reasonable to expect that the lifetime `'x` will always be less than `T`. ## Implementation Algorithm ## * Given a GAT `<P0 as Trait<P1..Pi>>::G<Pi...Pn>` declared as `trait T<A1..Ai> for A0 { type G<Ai...An>; }` used in return type of one associated function `F` * Given env `E` (including implied bounds) for `F` * For each lifetime parameter `'a` in `P0...Pn`: * For each other type parameter `Pi != 'a` in `P0...Pn`: // FIXME: this include of lifetime parameters too * If `E => (P: 'a)`: * Require where clause `Ai: 'a` ## Follow-up questions ## * What should we do when we don't pass params exactly? For this example: ```rust trait Des { type Out<'x, D>; fn des<'z, T>(&self, data: &'z Wrap<T>) -> Self::Out<'z, Wrap<T>>; } ``` Should we be requiring a `D: 'x` clause? We pass `Wrap<T>` as `D` and `'z` as `'x`, and should be able to prove that `Wrap<T>: 'z`. r? `@nikomatsakis`
This commit is contained in:
commit
9d39f6ab7d
22 changed files with 694 additions and 61 deletions
|
@ -1252,16 +1252,16 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
|||
self.tainted_by_errors_flag.set(true)
|
||||
}
|
||||
|
||||
/// Process the region constraints and report any errors that
|
||||
/// Process the region constraints and return any any errors that
|
||||
/// result. After this, no more unification operations should be
|
||||
/// done -- or the compiler will panic -- but it is legal to use
|
||||
/// `resolve_vars_if_possible` as well as `fully_resolve`.
|
||||
pub fn resolve_regions_and_report_errors(
|
||||
pub fn resolve_regions(
|
||||
&self,
|
||||
region_context: DefId,
|
||||
outlives_env: &OutlivesEnvironment<'tcx>,
|
||||
mode: RegionckMode,
|
||||
) {
|
||||
) -> Vec<RegionResolutionError<'tcx>> {
|
||||
let (var_infos, data) = {
|
||||
let mut inner = self.inner.borrow_mut();
|
||||
let inner = &mut *inner;
|
||||
|
@ -1287,6 +1287,21 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
|||
let old_value = self.lexical_region_resolutions.replace(Some(lexical_region_resolutions));
|
||||
assert!(old_value.is_none());
|
||||
|
||||
errors
|
||||
}
|
||||
|
||||
/// Process the region constraints and report any errors that
|
||||
/// result. After this, no more unification operations should be
|
||||
/// done -- or the compiler will panic -- but it is legal to use
|
||||
/// `resolve_vars_if_possible` as well as `fully_resolve`.
|
||||
pub fn resolve_regions_and_report_errors(
|
||||
&self,
|
||||
region_context: DefId,
|
||||
outlives_env: &OutlivesEnvironment<'tcx>,
|
||||
mode: RegionckMode,
|
||||
) {
|
||||
let errors = self.resolve_regions(region_context, outlives_env, mode);
|
||||
|
||||
if !self.is_tainted_by_errors() {
|
||||
// As a heuristic, just skip reporting region errors
|
||||
// altogether if other errors have been reported while
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue