Skip to content

Commit 9d39f6a

Browse files
committed
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`
2 parents 18cae26 + b6edcbd commit 9d39f6a

22 files changed

+694
-61
lines changed

compiler/rustc_infer/src/infer/mod.rs

+18-3
Original file line numberDiff line numberDiff line change
@@ -1252,16 +1252,16 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
12521252
self.tainted_by_errors_flag.set(true)
12531253
}
12541254

1255-
/// Process the region constraints and report any errors that
1255+
/// Process the region constraints and return any any errors that
12561256
/// result. After this, no more unification operations should be
12571257
/// done -- or the compiler will panic -- but it is legal to use
12581258
/// `resolve_vars_if_possible` as well as `fully_resolve`.
1259-
pub fn resolve_regions_and_report_errors(
1259+
pub fn resolve_regions(
12601260
&self,
12611261
region_context: DefId,
12621262
outlives_env: &OutlivesEnvironment<'tcx>,
12631263
mode: RegionckMode,
1264-
) {
1264+
) -> Vec<RegionResolutionError<'tcx>> {
12651265
let (var_infos, data) = {
12661266
let mut inner = self.inner.borrow_mut();
12671267
let inner = &mut *inner;
@@ -1287,6 +1287,21 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
12871287
let old_value = self.lexical_region_resolutions.replace(Some(lexical_region_resolutions));
12881288
assert!(old_value.is_none());
12891289

1290+
errors
1291+
}
1292+
1293+
/// Process the region constraints and report any errors that
1294+
/// result. After this, no more unification operations should be
1295+
/// done -- or the compiler will panic -- but it is legal to use
1296+
/// `resolve_vars_if_possible` as well as `fully_resolve`.
1297+
pub fn resolve_regions_and_report_errors(
1298+
&self,
1299+
region_context: DefId,
1300+
outlives_env: &OutlivesEnvironment<'tcx>,
1301+
mode: RegionckMode,
1302+
) {
1303+
let errors = self.resolve_regions(region_context, outlives_env, mode);
1304+
12901305
if !self.is_tainted_by_errors() {
12911306
// As a heuristic, just skip reporting region errors
12921307
// altogether if other errors have been reported while

compiler/rustc_typeck/src/check/regionck.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ macro_rules! ignore_err {
103103
};
104104
}
105105

106-
trait OutlivesEnvironmentExt<'tcx> {
106+
pub(crate) trait OutlivesEnvironmentExt<'tcx> {
107107
fn add_implied_bounds(
108108
&mut self,
109109
infcx: &InferCtxt<'a, 'tcx>,

0 commit comments

Comments
 (0)