]> git.lizzy.rs Git - rust.git/commitdiff
Auto merge of #98447 - JohnTitor:rollup-pponoo3, r=JohnTitor
authorbors <bors@rust-lang.org>
Fri, 24 Jun 2022 10:35:00 +0000 (10:35 +0000)
committerbors <bors@rust-lang.org>
Fri, 24 Jun 2022 10:35:00 +0000 (10:35 +0000)
Rollup of 9 pull requests

Successful merges:

 - #91264 (Add macro support in jump to definition feature)
 - #96955 (Remove (transitive) reliance on sorting by DefId in pretty-printer)
 - #97633 (Session object: Set OS/ABI)
 - #98039 (Fix `panic` message for `BTreeSet`'s `range` API and document `panic` cases)
 - #98214 (rustc_target: Remove some redundant target properties)
 - #98280 (Improve suggestion for calling fn-like expr on type mismatch)
 - #98394 (Fixup missing renames from `#[main]` to `#[rustc_main]`)
 - #98411 (Update tendril)
 - #98419 (Remove excess rib while resolving closures)

Failed merges:

r? `@ghost`
`@rustbot` modify labels: rollup

29 files changed:
compiler/rustc_borrowck/src/nll.rs
compiler/rustc_borrowck/src/region_infer/mod.rs
compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs
compiler/rustc_infer/src/infer/mod.rs
compiler/rustc_infer/src/infer/outlives/mod.rs
compiler/rustc_infer/src/infer/outlives/obligations.rs
compiler/rustc_infer/src/infer/outlives/test_type_match.rs [new file with mode: 0644]
compiler/rustc_infer/src/infer/outlives/verify.rs
compiler/rustc_infer/src/infer/region_constraints/mod.rs
src/test/ui/borrowck/issue-71546.rs
src/test/ui/borrowck/issue-71546.stderr [deleted file]
src/test/ui/generic-associated-types/collectivity-regression.rs [new file with mode: 0644]
src/test/ui/generic-associated-types/collectivity-regression.stderr [new file with mode: 0644]
src/test/ui/generic-associated-types/issue-86483.rs
src/test/ui/generic-associated-types/issue-86483.stderr [deleted file]
src/test/ui/generic-associated-types/issue-91139.rs
src/test/ui/generic-associated-types/issue-91139.stderr [new file with mode: 0644]
src/test/ui/generic-associated-types/issue-92096.rs
src/test/ui/generic-associated-types/issue-92096.stderr [new file with mode: 0644]
src/test/ui/higher-rank-trait-bounds/issue-88586-hr-self-outlives-in-trait-def.rs
src/test/ui/higher-rank-trait-bounds/issue-88586-hr-self-outlives-in-trait-def.stderr [deleted file]
src/test/ui/nll/snocat-regression.rs [new file with mode: 0644]
src/test/ui/nll/snocat-regression.stderr [new file with mode: 0644]
src/test/ui/nll/type-test-universe.rs [new file with mode: 0644]
src/test/ui/nll/type-test-universe.stderr [new file with mode: 0644]
src/test/ui/nll/vimwiki-core-regression.rs [new file with mode: 0644]
src/test/ui/regions/forall-wf-ref-reflexive.rs [new file with mode: 0644]
src/test/ui/regions/forall-wf-ref-reflexive.stderr [new file with mode: 0644]
src/test/ui/regions/forall-wf-reflexive.rs [new file with mode: 0644]

index 2440ae9780d230bacb50acdea0e082cbd9c12d37..3a919e954a424d350e4ef59cbea47cb34ba61177 100644 (file)
@@ -299,7 +299,7 @@ pub(crate) fn compute_regions<'cx, 'tcx>(
 
     // Solve the region constraints.
     let (closure_region_requirements, nll_errors) =
-        regioncx.solve(infcx, &body, polonius_output.clone());
+        regioncx.solve(infcx, param_env, &body, polonius_output.clone());
 
     if !nll_errors.is_empty() {
         // Suppress unhelpful extra errors in `infer_opaque_types`.
index fcb0978111ecb0cd379edb994640904fa7ffa9a3..0fe3b45bc7c4c30343070bc620408b060651f6c9 100644 (file)
@@ -10,7 +10,8 @@
 use rustc_hir::CRATE_HIR_ID;
 use rustc_index::vec::IndexVec;
 use rustc_infer::infer::canonical::QueryOutlivesConstraint;
-use rustc_infer::infer::region_constraints::{GenericKind, VarInfos, VerifyBound};
+use rustc_infer::infer::outlives::test_type_match;
+use rustc_infer::infer::region_constraints::{GenericKind, VarInfos, VerifyBound, VerifyIfEq};
 use rustc_infer::infer::{InferCtxt, NllRegionVariableOrigin, RegionVariableOrigin};
 use rustc_middle::mir::{
     Body, ClosureOutlivesRequirement, ClosureOutlivesSubject, ClosureRegionRequirements,
@@ -46,6 +47,7 @@
 
 pub struct RegionInferenceContext<'tcx> {
     pub var_infos: VarInfos,
+
     /// Contains the definition for every region variable. Region
     /// variables are identified by their index (`RegionVid`). The
     /// definition contains information about where the region came
@@ -559,6 +561,7 @@ pub(crate) fn applied_member_constraints(
     pub(super) fn solve(
         &mut self,
         infcx: &InferCtxt<'_, 'tcx>,
+        param_env: ty::ParamEnv<'tcx>,
         body: &Body<'tcx>,
         polonius_output: Option<Rc<PoloniusOutput>>,
     ) -> (Option<ClosureRegionRequirements<'tcx>>, RegionErrors<'tcx>) {
@@ -574,7 +577,13 @@ pub(super) fn solve(
         // eagerly.
         let mut outlives_requirements = infcx.tcx.is_typeck_child(mir_def_id).then(Vec::new);
 
-        self.check_type_tests(infcx, body, outlives_requirements.as_mut(), &mut errors_buffer);
+        self.check_type_tests(
+            infcx,
+            param_env,
+            body,
+            outlives_requirements.as_mut(),
+            &mut errors_buffer,
+        );
 
         // In Polonius mode, the errors about missing universal region relations are in the output
         // and need to be emitted or propagated. Otherwise, we need to check whether the
@@ -823,6 +832,7 @@ fn add_incompatible_universe(&mut self, scc: ConstraintSccIndex) {
     fn check_type_tests(
         &self,
         infcx: &InferCtxt<'_, 'tcx>,
+        param_env: ty::ParamEnv<'tcx>,
         body: &Body<'tcx>,
         mut propagated_outlives_requirements: Option<&mut Vec<ClosureOutlivesRequirement<'tcx>>>,
         errors_buffer: &mut RegionErrors<'tcx>,
@@ -839,7 +849,8 @@ fn check_type_tests(
 
             let generic_ty = type_test.generic_kind.to_ty(tcx);
             if self.eval_verify_bound(
-                tcx,
+                infcx,
+                param_env,
                 body,
                 generic_ty,
                 type_test.lower_bound,
@@ -851,6 +862,7 @@ fn check_type_tests(
             if let Some(propagated_outlives_requirements) = &mut propagated_outlives_requirements {
                 if self.try_promote_type_test(
                     infcx,
+                    param_env,
                     body,
                     type_test,
                     propagated_outlives_requirements,
@@ -907,6 +919,7 @@ fn check_type_tests(
     fn try_promote_type_test(
         &self,
         infcx: &InferCtxt<'_, 'tcx>,
+        param_env: ty::ParamEnv<'tcx>,
         body: &Body<'tcx>,
         type_test: &TypeTest<'tcx>,
         propagated_outlives_requirements: &mut Vec<ClosureOutlivesRequirement<'tcx>>,
@@ -938,7 +951,14 @@ fn try_promote_type_test(
             // where `ur` is a local bound -- we are sometimes in a
             // position to prove things that our caller cannot.  See
             // #53570 for an example.
-            if self.eval_verify_bound(tcx, body, generic_ty, ur, &type_test.verify_bound) {
+            if self.eval_verify_bound(
+                infcx,
+                param_env,
+                body,
+                generic_ty,
+                ur,
+                &type_test.verify_bound,
+            ) {
                 continue;
             }
 
@@ -1161,7 +1181,8 @@ pub(crate) fn approx_universal_upper_bound(&self, r: RegionVid) -> RegionVid {
     /// `point`.
     fn eval_verify_bound(
         &self,
-        tcx: TyCtxt<'tcx>,
+        infcx: &InferCtxt<'_, 'tcx>,
+        param_env: ty::ParamEnv<'tcx>,
         body: &Body<'tcx>,
         generic_ty: Ty<'tcx>,
         lower_bound: RegionVid,
@@ -1170,8 +1191,8 @@ fn eval_verify_bound(
         debug!("eval_verify_bound(lower_bound={:?}, verify_bound={:?})", lower_bound, verify_bound);
 
         match verify_bound {
-            VerifyBound::IfEq(test_ty, verify_bound1) => {
-                self.eval_if_eq(tcx, body, generic_ty, lower_bound, *test_ty, verify_bound1)
+            VerifyBound::IfEq(verify_if_eq_b) => {
+                self.eval_if_eq(infcx, param_env, generic_ty, lower_bound, *verify_if_eq_b)
             }
 
             VerifyBound::IsEmpty => {
@@ -1185,30 +1206,50 @@ fn eval_verify_bound(
             }
 
             VerifyBound::AnyBound(verify_bounds) => verify_bounds.iter().any(|verify_bound| {
-                self.eval_verify_bound(tcx, body, generic_ty, lower_bound, verify_bound)
+                self.eval_verify_bound(
+                    infcx,
+                    param_env,
+                    body,
+                    generic_ty,
+                    lower_bound,
+                    verify_bound,
+                )
             }),
 
             VerifyBound::AllBounds(verify_bounds) => verify_bounds.iter().all(|verify_bound| {
-                self.eval_verify_bound(tcx, body, generic_ty, lower_bound, verify_bound)
+                self.eval_verify_bound(
+                    infcx,
+                    param_env,
+                    body,
+                    generic_ty,
+                    lower_bound,
+                    verify_bound,
+                )
             }),
         }
     }
 
     fn eval_if_eq(
         &self,
-        tcx: TyCtxt<'tcx>,
-        body: &Body<'tcx>,
+        infcx: &InferCtxt<'_, 'tcx>,
+        param_env: ty::ParamEnv<'tcx>,
         generic_ty: Ty<'tcx>,
         lower_bound: RegionVid,
-        test_ty: Ty<'tcx>,
-        verify_bound: &VerifyBound<'tcx>,
+        verify_if_eq_b: ty::Binder<'tcx, VerifyIfEq<'tcx>>,
     ) -> bool {
-        let generic_ty_normalized = self.normalize_to_scc_representatives(tcx, generic_ty);
-        let test_ty_normalized = self.normalize_to_scc_representatives(tcx, test_ty);
-        if generic_ty_normalized == test_ty_normalized {
-            self.eval_verify_bound(tcx, body, generic_ty, lower_bound, verify_bound)
-        } else {
-            false
+        let generic_ty = self.normalize_to_scc_representatives(infcx.tcx, generic_ty);
+        let verify_if_eq_b = self.normalize_to_scc_representatives(infcx.tcx, verify_if_eq_b);
+        match test_type_match::extract_verify_if_eq(
+            infcx.tcx,
+            param_env,
+            &verify_if_eq_b,
+            generic_ty,
+        ) {
+            Some(r) => {
+                let r_vid = self.to_region_vid(r);
+                self.eval_outlives(r_vid, lower_bound)
+            }
+            None => false,
         }
     }
 
@@ -1278,6 +1319,18 @@ fn eval_outlives(&self, sup_region: RegionVid, sub_region: RegionVid) -> bool {
         let sub_region_scc = self.constraint_sccs.scc(sub_region);
         let sup_region_scc = self.constraint_sccs.scc(sup_region);
 
+        // If we are checking that `'sup: 'sub`, and `'sub` contains
+        // some placeholder that `'sup` cannot name, then this is only
+        // true if `'sup` outlives static.
+        if !self.universe_compatible(sub_region_scc, sup_region_scc) {
+            debug!(
+                "eval_outlives: sub universe `{sub_region_scc:?}` is not nameable \
+                by super `{sup_region_scc:?}`, promoting to static",
+            );
+
+            return self.eval_outlives(sup_region, self.universal_regions.fr_static);
+        }
+
         // Both the `sub_region` and `sup_region` consist of the union
         // of some number of universal regions (along with the union
         // of various points in the CFG; ignore those points for
@@ -1292,6 +1345,9 @@ fn eval_outlives(&self, sup_region: RegionVid, sub_region: RegionVid) -> bool {
             });
 
         if !universal_outlives {
+            debug!(
+                "eval_outlives: returning false because sub region contains a universal region not present in super"
+            );
             return false;
         }
 
@@ -1300,10 +1356,15 @@ fn eval_outlives(&self, sup_region: RegionVid, sub_region: RegionVid) -> bool {
 
         if self.universal_regions.is_universal_region(sup_region) {
             // Micro-opt: universal regions contain all points.
+            debug!(
+                "eval_outlives: returning true because super is universal and hence contains all points"
+            );
             return true;
         }
 
-        self.scc_values.contains_points(sup_region_scc, sub_region_scc)
+        let result = self.scc_values.contains_points(sup_region_scc, sub_region_scc);
+        debug!("returning {} because of comparison between points in sup/sub", result);
+        result
     }
 
     /// Once regions have been propagated, this method is used to see
index 7975b946ee5ba0f48caf75f7a156edbaee8aff91..455de47acef1b97e681f3dfdadcb203cf6f137ac 100644 (file)
@@ -22,6 +22,8 @@
 use rustc_span::Span;
 use std::fmt;
 
+use super::outlives::test_type_match;
+
 /// This function performs lexical region resolution given a complete
 /// set of constraints and variable origins. It performs a fixed-point
 /// iteration to find region values which satisfy all constraints,
 /// all the variables as well as a set of errors that must be reported.
 #[instrument(level = "debug", skip(region_rels, var_infos, data))]
 pub(crate) fn resolve<'tcx>(
+    param_env: ty::ParamEnv<'tcx>,
     region_rels: &RegionRelations<'_, 'tcx>,
     var_infos: VarInfos,
     data: RegionConstraintData<'tcx>,
 ) -> (LexicalRegionResolutions<'tcx>, Vec<RegionResolutionError<'tcx>>) {
     let mut errors = vec![];
-    let mut resolver = LexicalResolver { region_rels, var_infos, data };
+    let mut resolver = LexicalResolver { param_env, region_rels, var_infos, data };
     let values = resolver.infer_variable_values(&mut errors);
     (values, errors)
 }
@@ -100,6 +103,7 @@ struct RegionAndOrigin<'tcx> {
 type RegionGraph<'tcx> = Graph<(), Constraint<'tcx>>;
 
 struct LexicalResolver<'cx, 'tcx> {
+    param_env: ty::ParamEnv<'tcx>,
     region_rels: &'cx RegionRelations<'cx, 'tcx>,
     var_infos: VarInfos,
     data: RegionConstraintData<'tcx>,
@@ -818,9 +822,20 @@ fn bound_is_met(
         min: ty::Region<'tcx>,
     ) -> bool {
         match bound {
-            VerifyBound::IfEq(k, b) => {
-                (var_values.normalize(self.region_rels.tcx, *k) == generic_ty)
-                    && self.bound_is_met(b, var_values, generic_ty, min)
+            VerifyBound::IfEq(verify_if_eq_b) => {
+                let verify_if_eq_b = var_values.normalize(self.region_rels.tcx, *verify_if_eq_b);
+                match test_type_match::extract_verify_if_eq(
+                    self.tcx(),
+                    self.param_env,
+                    &verify_if_eq_b,
+                    generic_ty,
+                ) {
+                    Some(r) => {
+                        self.bound_is_met(&VerifyBound::OutlivedBy(r), var_values, generic_ty, min)
+                    }
+
+                    None => false,
+                }
             }
 
             VerifyBound::OutlivedBy(r) => {
index 93a067cb5160633e441a632fa43e621a1cb561a1..6f88b83a473213d86857bcb6dac01c57653a88e3 100644 (file)
@@ -1290,7 +1290,7 @@ pub fn resolve_regions(
             &RegionRelations::new(self.tcx, region_context, outlives_env.free_region_map());
 
         let (lexical_region_resolutions, errors) =
-            lexical_region_resolve::resolve(region_rels, var_infos, data);
+            lexical_region_resolve::resolve(outlives_env.param_env, region_rels, var_infos, data);
 
         let old_value = self.lexical_region_resolutions.replace(Some(lexical_region_resolutions));
         assert!(old_value.is_none());
index b9652e83e65bee227ea4b53a413391aae25ae5de..2a085288fb7c069c8d58d8a776b9e758d0b4078c 100644 (file)
@@ -3,6 +3,7 @@
 pub mod components;
 pub mod env;
 pub mod obligations;
+pub mod test_type_match;
 pub mod verify;
 
 use rustc_middle::traits::query::OutlivesBound;
index 2aa535da0e54cf1b26996511150025bba05256d5..a268493b28f631954047613056ee7bf26ec51ad6 100644 (file)
@@ -318,17 +318,13 @@ fn param_ty_must_outlive(
         self.delegate.push_verify(origin, generic, region, verify_bound);
     }
 
+    #[tracing::instrument(level = "debug", skip(self))]
     fn projection_must_outlive(
         &mut self,
         origin: infer::SubregionOrigin<'tcx>,
         region: ty::Region<'tcx>,
         projection_ty: ty::ProjectionTy<'tcx>,
     ) {
-        debug!(
-            "projection_must_outlive(region={:?}, projection_ty={:?}, origin={:?})",
-            region, projection_ty, origin
-        );
-
         // This case is thorny for inference. The fundamental problem is
         // that there are many cases where we have choice, and inference
         // doesn't like choice (the current region inference in
@@ -363,13 +359,21 @@ fn projection_must_outlive(
         // #55756) in cases where you have e.g., `<T as Foo<'a>>::Item:
         // 'a` in the environment but `trait Foo<'b> { type Item: 'b
         // }` in the trait definition.
-        approx_env_bounds.retain(|bound| match *bound.0.kind() {
-            ty::Projection(projection_ty) => self
-                .verify_bound
-                .projection_declared_bounds_from_trait(projection_ty)
-                .all(|r| r != bound.1),
-
-            _ => panic!("expected only projection types from env, not {:?}", bound.0),
+        approx_env_bounds.retain(|bound_outlives| {
+            // OK to skip binder because we only manipulate and compare against other
+            // values from the same binder. e.g. if we have (e.g.) `for<'a> <T as Trait<'a>>::Item: 'a`
+            // in `bound`, the `'a` will be a `^1` (bound, debruijn index == innermost) region.
+            // If the declaration is `trait Trait<'b> { type Item: 'b; }`, then `projection_declared_bounds_from_trait`
+            // will be invoked with `['b => ^1]` and so we will get `^1` returned.
+            let bound = bound_outlives.skip_binder();
+            match *bound.0.kind() {
+                ty::Projection(projection_ty) => self
+                    .verify_bound
+                    .projection_declared_bounds_from_trait(projection_ty)
+                    .all(|r| r != bound.1),
+
+                _ => panic!("expected only projection types from env, not {:?}", bound.0),
+            }
         });
 
         // If declared bounds list is empty, the only applicable rule is
@@ -420,8 +424,16 @@ fn projection_must_outlive(
         if !trait_bounds.is_empty()
             && trait_bounds[1..]
                 .iter()
-                .chain(approx_env_bounds.iter().map(|b| &b.1))
-                .all(|b| *b == trait_bounds[0])
+                .map(|r| Some(*r))
+                .chain(
+                    // NB: The environment may contain `for<'a> T: 'a` style bounds.
+                    // In that case, we don't know if they are equal to the trait bound
+                    // or not (since we don't *know* whether the environment bound even applies),
+                    // so just map to `None` here if there are bound vars, ensuring that
+                    // the call to `all` will fail below.
+                    approx_env_bounds.iter().map(|b| b.map_bound(|b| b.1).no_bound_vars()),
+                )
+                .all(|b| b == Some(trait_bounds[0]))
         {
             let unique_bound = trait_bounds[0];
             debug!("projection_must_outlive: unique trait bound = {:?}", unique_bound);
@@ -437,6 +449,7 @@ fn projection_must_outlive(
         // even though a satisfactory solution exists.
         let generic = GenericKind::Projection(projection_ty);
         let verify_bound = self.verify_bound.generic_bound(generic);
+        debug!("projection_must_outlive: pushing {:?}", verify_bound);
         self.delegate.push_verify(origin, generic, region, verify_bound);
     }
 }
diff --git a/compiler/rustc_infer/src/infer/outlives/test_type_match.rs b/compiler/rustc_infer/src/infer/outlives/test_type_match.rs
new file mode 100644 (file)
index 0000000..9f71eba
--- /dev/null
@@ -0,0 +1,207 @@
+use std::collections::hash_map::Entry;
+
+use rustc_data_structures::fx::FxHashMap;
+use rustc_middle::ty::TypeFoldable;
+use rustc_middle::ty::{
+    self,
+    error::TypeError,
+    relate::{self, Relate, RelateResult, TypeRelation},
+    Ty, TyCtxt,
+};
+
+use crate::infer::region_constraints::VerifyIfEq;
+
+/// Given a "verify-if-eq" type test like:
+///
+///     exists<'a...> {
+///         verify_if_eq(some_type, bound_region)
+///     }
+///
+/// and the type `test_ty` that the type test is being tested against,
+/// returns:
+///
+/// * `None` if `some_type` cannot be made equal to `test_ty`,
+///   no matter the values of the variables in `exists`.
+/// * `Some(r)` with a suitable bound (typically the value of `bound_region`, modulo
+///   any bound existential variables, which will be substituted) for the
+///   type under test.
+///
+/// NB: This function uses a simplistic, syntactic version of type equality.
+/// In other words, it may spuriously return `None` even if the type-under-test
+/// is in fact equal to `some_type`. In practice, though, this is used on types
+/// that are either projections like `T::Item` or `T` and it works fine, but it
+/// could have trouble when complex types with higher-ranked binders and the
+/// like are used. This is a particular challenge since this function is invoked
+/// very late in inference and hence cannot make use of the normal inference
+/// machinery.
+#[tracing::instrument(level = "debug", skip(tcx, param_env))]
+pub fn extract_verify_if_eq<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    param_env: ty::ParamEnv<'tcx>,
+    verify_if_eq_b: &ty::Binder<'tcx, VerifyIfEq<'tcx>>,
+    test_ty: Ty<'tcx>,
+) -> Option<ty::Region<'tcx>> {
+    assert!(!verify_if_eq_b.has_escaping_bound_vars());
+    let mut m = Match::new(tcx, param_env);
+    let verify_if_eq = verify_if_eq_b.skip_binder();
+    m.relate(verify_if_eq.ty, test_ty).ok()?;
+
+    if let ty::RegionKind::ReLateBound(depth, br) = verify_if_eq.bound.kind() {
+        assert!(depth == ty::INNERMOST);
+        match m.map.get(&br) {
+            Some(&r) => Some(r),
+            None => {
+                // If there is no mapping, then this region is unconstrained.
+                // In that case, we escalate to `'static`.
+                Some(tcx.lifetimes.re_static)
+            }
+        }
+    } else {
+        // The region does not contain any bound variables, so we don't need
+        // to do any substitution.
+        //
+        // Example:
+        //
+        // for<'a> <T as Foo<'a>>::Item: 'b
+        //
+        // In this case, we've now matched and found a value for
+        // `'a`, but it doesn't affect the bound `'b`.
+        Some(verify_if_eq.bound)
+    }
+}
+
+/// True if a (potentially higher-ranked) outlives
+#[tracing::instrument(level = "debug", skip(tcx, param_env))]
+pub(super) fn can_match_erased_ty<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    param_env: ty::ParamEnv<'tcx>,
+    outlives_predicate: ty::Binder<'tcx, ty::TypeOutlivesPredicate<'tcx>>,
+    erased_ty: Ty<'tcx>,
+) -> bool {
+    assert!(!outlives_predicate.has_escaping_bound_vars());
+    let erased_outlives_predicate = tcx.erase_regions(outlives_predicate);
+    let outlives_ty = erased_outlives_predicate.skip_binder().0;
+    if outlives_ty == erased_ty {
+        // pointless micro-optimization
+        true
+    } else {
+        Match::new(tcx, param_env).relate(outlives_ty, erased_ty).is_ok()
+    }
+}
+
+struct Match<'tcx> {
+    tcx: TyCtxt<'tcx>,
+    param_env: ty::ParamEnv<'tcx>,
+    pattern_depth: ty::DebruijnIndex,
+    map: FxHashMap<ty::BoundRegion, ty::Region<'tcx>>,
+}
+
+impl<'tcx> Match<'tcx> {
+    fn new(tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> Match<'tcx> {
+        Match { tcx, param_env, pattern_depth: ty::INNERMOST, map: FxHashMap::default() }
+    }
+}
+
+impl<'tcx> Match<'tcx> {
+    /// Creates the "Error" variant that signals "no match".
+    fn no_match<T>(&self) -> RelateResult<'tcx, T> {
+        Err(TypeError::Mismatch)
+    }
+
+    /// Binds the pattern variable `br` to `value`; returns an `Err` if the pattern
+    /// is already bound to a different value.
+    #[tracing::instrument(level = "debug", skip(self))]
+    fn bind(
+        &mut self,
+        br: ty::BoundRegion,
+        value: ty::Region<'tcx>,
+    ) -> RelateResult<'tcx, ty::Region<'tcx>> {
+        match self.map.entry(br) {
+            Entry::Occupied(entry) => {
+                if *entry.get() == value {
+                    Ok(value)
+                } else {
+                    self.no_match()
+                }
+            }
+            Entry::Vacant(entry) => {
+                entry.insert(value);
+                Ok(value)
+            }
+        }
+    }
+}
+
+impl<'tcx> TypeRelation<'tcx> for Match<'tcx> {
+    fn tag(&self) -> &'static str {
+        "Match"
+    }
+    fn tcx(&self) -> TyCtxt<'tcx> {
+        self.tcx
+    }
+    fn param_env(&self) -> ty::ParamEnv<'tcx> {
+        self.param_env
+    }
+    fn a_is_expected(&self) -> bool {
+        true
+    } // irrelevant
+
+    fn relate_with_variance<T: Relate<'tcx>>(
+        &mut self,
+        _: ty::Variance,
+        _: ty::VarianceDiagInfo<'tcx>,
+        a: T,
+        b: T,
+    ) -> RelateResult<'tcx, T> {
+        self.relate(a, b)
+    }
+
+    #[instrument(skip(self), level = "debug")]
+    fn regions(
+        &mut self,
+        pattern: ty::Region<'tcx>,
+        value: ty::Region<'tcx>,
+    ) -> RelateResult<'tcx, ty::Region<'tcx>> {
+        debug!("self.pattern_depth = {:?}", self.pattern_depth);
+        if let ty::RegionKind::ReLateBound(depth, br) = pattern.kind() && depth == self.pattern_depth {
+            self.bind(br, value)
+        } else if pattern == value {
+            Ok(pattern)
+        } else {
+            self.no_match()
+        }
+    }
+
+    #[instrument(skip(self), level = "debug")]
+    fn tys(&mut self, pattern: Ty<'tcx>, value: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
+        if pattern == value { Ok(pattern) } else { relate::super_relate_tys(self, pattern, value) }
+    }
+
+    #[instrument(skip(self), level = "debug")]
+    fn consts(
+        &mut self,
+        pattern: ty::Const<'tcx>,
+        value: ty::Const<'tcx>,
+    ) -> RelateResult<'tcx, ty::Const<'tcx>> {
+        debug!("{}.consts({:?}, {:?})", self.tag(), pattern, value);
+        if pattern == value {
+            Ok(pattern)
+        } else {
+            relate::super_relate_consts(self, pattern, value)
+        }
+    }
+
+    fn binders<T>(
+        &mut self,
+        pattern: ty::Binder<'tcx, T>,
+        value: ty::Binder<'tcx, T>,
+    ) -> RelateResult<'tcx, ty::Binder<'tcx, T>>
+    where
+        T: Relate<'tcx>,
+    {
+        self.pattern_depth.shift_in(1);
+        let result = Ok(pattern.rebind(self.relate(pattern.skip_binder(), value.skip_binder())?));
+        self.pattern_depth.shift_out(1);
+        result
+    }
+}
index 1c521c90686d6c0bf3392268bd405bd94fd29312..191f5f18ec2a6e818bbc6e941f4b7f2324b306ac 100644 (file)
@@ -1,4 +1,5 @@
 use crate::infer::outlives::env::RegionBoundPairs;
+use crate::infer::region_constraints::VerifyIfEq;
 use crate::infer::{GenericKind, VerifyBound};
 use rustc_data_structures::captures::Captures;
 use rustc_data_structures::sso::SsoHashSet;
@@ -82,27 +83,39 @@ fn param_bound(&self, param_ty: ty::ParamTy) -> VerifyBound<'tcx> {
         debug!("param_bound(param_ty={:?})", param_ty);
 
         // Start with anything like `T: 'a` we can scrape from the
-        // environment
-        let param_bounds = self
-            .declared_generic_bounds_from_env(GenericKind::Param(param_ty))
-            .into_iter()
-            .map(|outlives| outlives.1);
+        // environment. If the environment contains something like
+        // `for<'a> T: 'a`, then we know that `T` outlives everything.
+        let declared_bounds_from_env = self.declared_generic_bounds_from_env(param_ty);
+        let mut param_bounds = vec![];
+        for declared_bound in declared_bounds_from_env {
+            let bound_region = declared_bound.map_bound(|outlives| outlives.1);
+            if let Some(region) = bound_region.no_bound_vars() {
+                // This is `T: 'a` for some free region `'a`.
+                param_bounds.push(VerifyBound::OutlivedBy(region));
+            } else {
+                // This is `for<'a> T: 'a`. This means that `T` outlives everything! All done here.
+                return VerifyBound::AllBounds(vec![]);
+            }
+        }
 
         // Add in the default bound of fn body that applies to all in
         // scope type parameters:
-        let param_bounds = param_bounds.chain(self.implicit_region_bound);
-
-        let any_bounds: Vec<_> = param_bounds.map(|r| VerifyBound::OutlivedBy(r)).collect();
+        if let Some(r) = self.implicit_region_bound {
+            param_bounds.push(VerifyBound::OutlivedBy(r));
+        }
 
-        if any_bounds.is_empty() {
+        if param_bounds.is_empty() {
             // We know that all types `T` outlive `'empty`, so if we
             // can find no other bound, then check that the region
             // being tested is `'empty`.
             VerifyBound::IsEmpty
+        } else if param_bounds.len() == 1 {
+            // Micro-opt: no need to store the vector if it's just len 1
+            param_bounds.pop().unwrap()
         } else {
             // If we can find any other bound `R` such that `T: R`, then
             // we don't need to check for `'empty`, because `R: 'empty`.
-            VerifyBound::AnyBound(any_bounds)
+            VerifyBound::AnyBound(param_bounds)
         }
     }
 
@@ -122,17 +135,10 @@ fn param_bound(&self, param_ty: ty::ParamTy) -> VerifyBound<'tcx> {
     pub fn projection_approx_declared_bounds_from_env(
         &self,
         projection_ty: ty::ProjectionTy<'tcx>,
-    ) -> Vec<ty::OutlivesPredicate<Ty<'tcx>, ty::Region<'tcx>>> {
+    ) -> Vec<ty::Binder<'tcx, ty::OutlivesPredicate<Ty<'tcx>, ty::Region<'tcx>>>> {
         let projection_ty = GenericKind::Projection(projection_ty).to_ty(self.tcx);
         let erased_projection_ty = self.tcx.erase_regions(projection_ty);
-        self.declared_generic_bounds_from_env_with_compare_fn(|ty| {
-            if let ty::Projection(..) = ty.kind() {
-                let erased_ty = self.tcx.erase_regions(ty);
-                erased_ty == erased_projection_ty
-            } else {
-                false
-            }
-        })
+        self.declared_generic_bounds_from_env_for_erased_ty(erased_projection_ty)
     }
 
     /// Searches the where-clauses in scope for regions that
@@ -159,15 +165,15 @@ pub fn projection_bound(
         let env_bounds = self
             .projection_approx_declared_bounds_from_env(projection_ty)
             .into_iter()
-            .map(|ty::OutlivesPredicate(ty, r)| {
-                let vb = VerifyBound::OutlivedBy(r);
-                if ty == projection_ty_as_ty {
+            .map(|binder| {
+                if let Some(ty::OutlivesPredicate(ty, r)) = binder.no_bound_vars() && ty == projection_ty_as_ty {
                     // Micro-optimize if this is an exact match (this
                     // occurs often when there are no region variables
                     // involved).
-                    vb
+                    VerifyBound::OutlivedBy(r)
                 } else {
-                    VerifyBound::IfEq(ty, Box::new(vb))
+                    let verify_if_eq_b = binder.map_bound(|ty::OutlivesPredicate(ty, bound)| VerifyIfEq { ty, bound });
+                    VerifyBound::IfEq(verify_if_eq_b)
                 }
             });
 
@@ -219,26 +225,34 @@ fn recursive_bound(
     /// bounds, but all the bounds it returns can be relied upon.
     fn declared_generic_bounds_from_env(
         &self,
-        generic: GenericKind<'tcx>,
-    ) -> Vec<ty::OutlivesPredicate<Ty<'tcx>, ty::Region<'tcx>>> {
-        let generic_ty = generic.to_ty(self.tcx);
-        self.declared_generic_bounds_from_env_with_compare_fn(|ty| ty == generic_ty)
+        param_ty: ty::ParamTy,
+    ) -> Vec<ty::Binder<'tcx, ty::OutlivesPredicate<Ty<'tcx>, ty::Region<'tcx>>>> {
+        let generic_ty = param_ty.to_ty(self.tcx);
+        self.declared_generic_bounds_from_env_for_erased_ty(generic_ty)
     }
 
-    fn declared_generic_bounds_from_env_with_compare_fn(
+    /// Searches the environment to find all bounds that apply to `erased_ty`.
+    /// Obviously these must be approximate -- they are in fact both *over* and
+    /// and *under* approximated:
+    ///
+    /// * Over-approximated because we erase regions, so
+    /// * Under-approximated because we look for syntactic equality and so for complex types
+    ///   like `<T as Foo<fn(&u32, &u32)>>::Item` or whatever we may fail to figure out
+    ///   all the subtleties.
+    ///
+    /// In some cases, such as when `erased_ty` represents a `ty::Param`, however,
+    /// the result is precise.
+    fn declared_generic_bounds_from_env_for_erased_ty(
         &self,
-        compare_ty: impl Fn(Ty<'tcx>) -> bool,
-    ) -> Vec<ty::OutlivesPredicate<Ty<'tcx>, ty::Region<'tcx>>> {
+        erased_ty: Ty<'tcx>,
+    ) -> Vec<ty::Binder<'tcx, ty::OutlivesPredicate<Ty<'tcx>, ty::Region<'tcx>>>> {
         let tcx = self.tcx;
 
         // To start, collect bounds from user environment. Note that
         // parameter environments are already elaborated, so we don't
-        // have to worry about that. Comparing using `==` is a bit
-        // dubious for projections, but it will work for simple cases
-        // like `T` and `T::Item`. It may not work as well for things
-        // like `<T as Foo<'a>>::Item`.
+        // have to worry about that.
         let c_b = self.param_env.caller_bounds();
-        let param_bounds = self.collect_outlives_from_predicate_list(&compare_ty, c_b.into_iter());
+        let param_bounds = self.collect_outlives_from_predicate_list(erased_ty, c_b.into_iter());
 
         // Next, collect regions we scraped from the well-formedness
         // constraints in the fn signature. To do that, we walk the list
@@ -253,18 +267,20 @@ fn declared_generic_bounds_from_env_with_compare_fn(
         // don't know that this holds from first principles.
         let from_region_bound_pairs = self.region_bound_pairs.iter().filter_map(|&(r, p)| {
             debug!(
-                "declared_generic_bounds_from_env_with_compare_fn: region_bound_pair = {:?}",
+                "declared_generic_bounds_from_env_for_erased_ty: region_bound_pair = {:?}",
                 (r, p)
             );
             let p_ty = p.to_ty(tcx);
-            compare_ty(p_ty).then_some(ty::OutlivesPredicate(p_ty, r))
+            let erased_p_ty = self.tcx.erase_regions(p_ty);
+            (erased_p_ty == erased_ty)
+                .then_some(ty::Binder::dummy(ty::OutlivesPredicate(p.to_ty(tcx), r)))
         });
 
         param_bounds
             .chain(from_region_bound_pairs)
             .inspect(|bound| {
                 debug!(
-                    "declared_generic_bounds_from_env_with_compare_fn: result predicate = {:?}",
+                    "declared_generic_bounds_from_env_for_erased_ty: result predicate = {:?}",
                     bound
                 )
             })
@@ -344,12 +360,19 @@ fn region_bounds_declared_on_associated_item(
     /// otherwise want a precise match.
     fn collect_outlives_from_predicate_list(
         &self,
-        compare_ty: impl Fn(Ty<'tcx>) -> bool,
+        erased_ty: Ty<'tcx>,
         predicates: impl Iterator<Item = ty::Predicate<'tcx>>,
-    ) -> impl Iterator<Item = ty::OutlivesPredicate<Ty<'tcx>, ty::Region<'tcx>>> {
-        predicates
-            .filter_map(|p| p.to_opt_type_outlives())
-            .filter_map(|p| p.no_bound_vars())
-            .filter(move |p| compare_ty(p.0))
+    ) -> impl Iterator<Item = ty::Binder<'tcx, ty::OutlivesPredicate<Ty<'tcx>, ty::Region<'tcx>>>>
+    {
+        let tcx = self.tcx;
+        let param_env = self.param_env;
+        predicates.filter_map(|p| p.to_opt_type_outlives()).filter(move |outlives_predicate| {
+            super::test_type_match::can_match_erased_ty(
+                tcx,
+                param_env,
+                *outlives_predicate,
+                erased_ty,
+            )
+        })
     }
 }
index efe254387dcc94957934758af86c2c626b8ee3ae..19f83e3377a675248103a238a6b0f9f6d0e90e40 100644 (file)
@@ -190,41 +190,8 @@ pub enum GenericKind<'tcx> {
 /// This is described with an `AnyRegion('a, 'b)` node.
 #[derive(Debug, Clone)]
 pub enum VerifyBound<'tcx> {
-    /// Given a kind K and a bound B, expands to a function like the
-    /// following, where `G` is the generic for which this verify
-    /// bound was created:
-    ///
-    /// ```ignore (pseudo-rust)
-    /// fn(min) -> bool {
-    ///     if G == K {
-    ///         B(min)
-    ///     } else {
-    ///         false
-    ///     }
-    /// }
-    /// ```
-    ///
-    /// In other words, if the generic `G` that we are checking is
-    /// equal to `K`, then check the associated verify bound
-    /// (otherwise, false).
-    ///
-    /// This is used when we have something in the environment that
-    /// may or may not be relevant, depending on the region inference
-    /// results. For example, we may have `where <T as
-    /// Trait<'a>>::Item: 'b` in our where-clauses. If we are
-    /// generating the verify-bound for `<T as Trait<'0>>::Item`, then
-    /// this where-clause is only relevant if `'0` winds up inferred
-    /// to `'a`.
-    ///
-    /// So we would compile to a verify-bound like
-    ///
-    /// ```ignore (illustrative)
-    /// IfEq(<T as Trait<'a>>::Item, AnyRegion('a))
-    /// ```
-    ///
-    /// meaning, if the subject G is equal to `<T as Trait<'a>>::Item`
-    /// (after inference), and `'a: min`, then `G: min`.
-    IfEq(Ty<'tcx>, Box<VerifyBound<'tcx>>),
+    /// See [`VerifyIfEq`] docs
+    IfEq(ty::Binder<'tcx, VerifyIfEq<'tcx>>),
 
     /// Given a region `R`, expands to the function:
     ///
@@ -267,6 +234,53 @@ pub enum VerifyBound<'tcx> {
     AllBounds(Vec<VerifyBound<'tcx>>),
 }
 
+/// This is a "conditional bound" that checks the result of inference
+/// and supplies a bound if it ended up being relevant. It's used in situations
+/// like this:
+///
+/// ```rust
+/// fn foo<'a, 'b, T: SomeTrait<'a>>
+/// where
+///    <T as SomeTrait<'a>>::Item: 'b
+/// ```
+///
+/// If we have an obligation like `<T as SomeTrait<'?x>>::Item: 'c`, then
+/// we don't know yet whether it suffices to show that `'b: 'c`. If `'?x` winds
+/// up being equal to `'a`, then the where-clauses on function applies, and
+/// in that case we can show `'b: 'c`. But if `'?x` winds up being something
+/// else, the bound isn't relevant.
+///
+/// In the [`VerifyBound`], this struct is enclosed in `Binder to account
+/// for cases like
+///
+/// ```rust
+/// where for<'a> <T as SomeTrait<'a>::Item: 'a
+/// ```
+///
+/// The idea is that we have to find some instantiation of `'a` that can
+/// make `<T as SomeTrait<'a>>::Item` equal to the final value of `G`,
+/// the generic we are checking.
+///
+/// ```ignore (pseudo-rust)
+/// fn(min) -> bool {
+///     exists<'a> {
+///         if G == K {
+///             B(min)
+///         } else {
+///             false
+///         }
+///     }
+/// }
+/// ```
+#[derive(Debug, Copy, Clone, TypeFoldable)]
+pub struct VerifyIfEq<'tcx> {
+    /// Type which must match the generic `G`
+    pub ty: Ty<'tcx>,
+
+    /// Bound that applies if `ty` is equal.
+    pub bound: Region<'tcx>,
+}
+
 #[derive(Copy, Clone, PartialEq, Eq, Hash)]
 pub(crate) struct TwoRegions<'tcx> {
     a: Region<'tcx>,
@@ -770,7 +784,7 @@ pub fn must_hold(&self) -> bool {
 
     pub fn cannot_hold(&self) -> bool {
         match self {
-            VerifyBound::IfEq(_, b) => b.cannot_hold(),
+            VerifyBound::IfEq(..) => false,
             VerifyBound::IsEmpty => false,
             VerifyBound::OutlivedBy(_) => false,
             VerifyBound::AnyBound(bs) => bs.iter().all(|b| b.cannot_hold()),
index b20c39193de39daf554f916c8e684295fc7b2848..42100edeaa7125d40dfda579781f6b960d5a593e 100644 (file)
@@ -1,4 +1,8 @@
 // Regression test for #71546.
+//
+// Made to pass as part of fixing #98095.
+//
+// check-pass
 
 pub fn serialize_as_csv<V>(value: &V) -> Result<String, &str>
 where
@@ -6,15 +10,7 @@ pub fn serialize_as_csv<V>(value: &V) -> Result<String, &str>
     for<'a> &'a V: IntoIterator,
     for<'a> <&'a V as IntoIterator>::Item: ToString + 'static,
 {
-    let csv_str: String = value
-        //~^ ERROR higher-ranked lifetime error
-        //~| ERROR higher-ranked lifetime error
-        //~| ERROR higher-ranked lifetime error
-        .into_iter()
-        .map(|elem| elem.to_string())
-        //~^ ERROR higher-ranked lifetime error
-        .collect::<String>();
-        //~^ ERROR higher-ranked lifetime error
+    let csv_str: String = value.into_iter().map(|elem| elem.to_string()).collect::<String>();
     Ok(csv_str)
 }
 
diff --git a/src/test/ui/borrowck/issue-71546.stderr b/src/test/ui/borrowck/issue-71546.stderr
deleted file mode 100644 (file)
index b8d79f0..0000000
+++ /dev/null
@@ -1,59 +0,0 @@
-error: higher-ranked lifetime error
-  --> $DIR/issue-71546.rs:9:27
-   |
-LL |       let csv_str: String = value
-   |  ___________________________^
-LL | |
-LL | |
-LL | |
-LL | |         .into_iter()
-LL | |         .map(|elem| elem.to_string())
-   | |_____________________________________^
-   |
-   = note: could not prove for<'r> [closure@$DIR/issue-71546.rs:14:14: 14:37] well-formed
-
-error: higher-ranked lifetime error
-  --> $DIR/issue-71546.rs:9:27
-   |
-LL |       let csv_str: String = value
-   |  ___________________________^
-LL | |
-LL | |
-LL | |
-LL | |         .into_iter()
-LL | |         .map(|elem| elem.to_string())
-   | |_____________________________________^
-   |
-   = note: could not prove for<'r, 's> Map<<&'r V as IntoIterator>::IntoIter, [closure@$DIR/issue-71546.rs:14:14: 14:37]> well-formed
-
-error: higher-ranked lifetime error
-  --> $DIR/issue-71546.rs:9:27
-   |
-LL |       let csv_str: String = value
-   |  ___________________________^
-LL | |
-LL | |
-LL | |
-...  |
-LL | |
-LL | |         .collect::<String>();
-   | |____________________________^
-   |
-   = note: could not prove for<'r, 's> Map<<&'r V as IntoIterator>::IntoIter, [closure@$DIR/issue-71546.rs:14:14: 14:37]> well-formed
-
-error: higher-ranked lifetime error
-  --> $DIR/issue-71546.rs:14:14
-   |
-LL |         .map(|elem| elem.to_string())
-   |              ^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: could not prove for<'a> <&'a V as IntoIterator>::Item: 'static
-
-error: higher-ranked lifetime error
-  --> $DIR/issue-71546.rs:16:10
-   |
-LL |         .collect::<String>();
-   |          ^^^^^^^
-
-error: aborting due to 5 previous errors
-
diff --git a/src/test/ui/generic-associated-types/collectivity-regression.rs b/src/test/ui/generic-associated-types/collectivity-regression.rs
new file mode 100644 (file)
index 0000000..fb73684
--- /dev/null
@@ -0,0 +1,24 @@
+// Regression test from https://github.com/rust-lang/rust/pull/98109
+
+#![feature(generic_associated_types)]
+
+pub trait Get {
+    type Value<'a>
+    where
+        Self: 'a;
+}
+
+fn multiply_at<T>(x: T)
+where
+    for<'a> T: Get<Value<'a> = ()>,
+{
+    || {
+        //~^ `T` does not live long enough
+        //
+        // FIXME(#98437). This regressed at some point and
+        // probably should work.
+        let _x = x;
+    };
+}
+
+fn main() {}
diff --git a/src/test/ui/generic-associated-types/collectivity-regression.stderr b/src/test/ui/generic-associated-types/collectivity-regression.stderr
new file mode 100644 (file)
index 0000000..a858dd7
--- /dev/null
@@ -0,0 +1,14 @@
+error: `T` does not live long enough
+  --> $DIR/collectivity-regression.rs:15:5
+   |
+LL | /     || {
+LL | |
+LL | |         //
+LL | |         // FIXME(#98437). This regressed at some point and
+LL | |         // probably should work.
+LL | |         let _x = x;
+LL | |     };
+   | |_____^
+
+error: aborting due to previous error
+
index a8b54c354e3f3e35afb1365be8f81627f7cd3039..07dd0bffd4685900d5db37878e472cc05fea3fb7 100644 (file)
@@ -1,14 +1,16 @@
 // Regression test of #86483.
+//
+// Made to pass as part of fixing #98095.
+//
+// check-pass
 
 #![feature(generic_associated_types)]
 
-pub trait IceIce<T> //~ ERROR: the parameter type `T` may not live long enough
+pub trait IceIce<T>
 where
     for<'a> T: 'a,
 {
     type Ice<'v>: IntoIterator<Item = &'v T>;
-    //~^ ERROR: the parameter type `T` may not live long enough
-    //~| ERROR: the parameter type `T` may not live long enough
 }
 
 fn main() {}
diff --git a/src/test/ui/generic-associated-types/issue-86483.stderr b/src/test/ui/generic-associated-types/issue-86483.stderr
deleted file mode 100644 (file)
index a13dc04..0000000
+++ /dev/null
@@ -1,50 +0,0 @@
-error[E0311]: the parameter type `T` may not live long enough
-  --> $DIR/issue-86483.rs:5:1
-   |
-LL | / pub trait IceIce<T>
-LL | | where
-LL | |     for<'a> T: 'a,
-LL | | {
-...  |
-LL | |
-LL | | }
-   | |_^
-   |
-   = note: ...so that the type `T` will meet its required lifetime bounds...
-note: ...that is required by this bound
-  --> $DIR/issue-86483.rs:7:16
-   |
-LL |     for<'a> T: 'a,
-   |                ^^
-help: consider adding an explicit lifetime bound...
-   |
-LL |     for<'a> T: 'a + 'a,
-   |                   ++++
-
-error[E0311]: the parameter type `T` may not live long enough
-  --> $DIR/issue-86483.rs:9:5
-   |
-LL |     type Ice<'v>: IntoIterator<Item = &'v T>;
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds...
-   |
-note: ...that is required by this bound
-  --> $DIR/issue-86483.rs:7:16
-   |
-LL |     for<'a> T: 'a,
-   |                ^^
-help: consider adding an explicit lifetime bound...
-   |
-LL |     for<'a> T: 'a + 'a,
-   |                   ++++
-
-error[E0309]: the parameter type `T` may not live long enough
-  --> $DIR/issue-86483.rs:9:32
-   |
-LL |     type Ice<'v>: IntoIterator<Item = &'v T>;
-   |                                ^^^^^^^^^^^^ - help: consider adding a where clause: `where T: 'v`
-   |                                |
-   |                                ...so that the reference type `&'v T` does not outlive the data it points at
-
-error: aborting due to 3 previous errors
-
-For more information about this error, try `rustc --explain E0309`.
index 03dc8ef93fe3ac80949f39107058b42687d6a56f..092fa939c308d5d9a3899d99c667c1d6562c46a5 100644 (file)
@@ -1,5 +1,3 @@
-//check-pass
-
 #![feature(generic_associated_types)]
 
 trait Foo<T> {
@@ -16,6 +14,22 @@ impl<T> Foo<T> for () {
 
 fn foo<T>() {
     let _: for<'a> fn(<() as Foo<T>>::Type<'a>, &'a T) = |_, _| ();
+    //~^ ERROR `T` does not live long enough
+    //~| ERROR `T` does not live long enough
+    //~| ERROR `T` does not live long enough
+    //~| ERROR `T` does not live long enough
+    //~| ERROR `T` does not live long enough
+    //~| ERROR `T` does not live long enough
+    //~| ERROR `T` does not live long enough
+    //~| ERROR `T` does not live long enough
+    //
+    // FIXME: This error is bogus, but it arises because we try to validate
+    // that `<() as Foo<T>>::Type<'a>` is valid, which requires proving
+    // that `T: 'a`. Since `'a` is higher-ranked, this becomes
+    // `for<'a> T: 'a`, which is not true. Of course, the error is bogus
+    // because there *ought* to be an implied bound stating that `'a` is
+    // not any lifetime but specifically
+    // "some `'a` such that `<() as Foo<T>>::Type<'a>" is valid".
 }
 
 pub fn main() {}
diff --git a/src/test/ui/generic-associated-types/issue-91139.stderr b/src/test/ui/generic-associated-types/issue-91139.stderr
new file mode 100644 (file)
index 0000000..6c50929
--- /dev/null
@@ -0,0 +1,50 @@
+error: `T` does not live long enough
+  --> $DIR/issue-91139.rs:16:12
+   |
+LL |     let _: for<'a> fn(<() as Foo<T>>::Type<'a>, &'a T) = |_, _| ();
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: `T` does not live long enough
+  --> $DIR/issue-91139.rs:16:12
+   |
+LL |     let _: for<'a> fn(<() as Foo<T>>::Type<'a>, &'a T) = |_, _| ();
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: `T` does not live long enough
+  --> $DIR/issue-91139.rs:16:12
+   |
+LL |     let _: for<'a> fn(<() as Foo<T>>::Type<'a>, &'a T) = |_, _| ();
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: `T` does not live long enough
+  --> $DIR/issue-91139.rs:16:12
+   |
+LL |     let _: for<'a> fn(<() as Foo<T>>::Type<'a>, &'a T) = |_, _| ();
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: `T` does not live long enough
+  --> $DIR/issue-91139.rs:16:58
+   |
+LL |     let _: for<'a> fn(<() as Foo<T>>::Type<'a>, &'a T) = |_, _| ();
+   |                                                          ^^^^^^^^^
+
+error: `T` does not live long enough
+  --> $DIR/issue-91139.rs:16:58
+   |
+LL |     let _: for<'a> fn(<() as Foo<T>>::Type<'a>, &'a T) = |_, _| ();
+   |                                                          ^^^^^^^^^
+
+error: `T` does not live long enough
+  --> $DIR/issue-91139.rs:16:58
+   |
+LL |     let _: for<'a> fn(<() as Foo<T>>::Type<'a>, &'a T) = |_, _| ();
+   |                                                          ^^^^^^^^^
+
+error: `T` does not live long enough
+  --> $DIR/issue-91139.rs:16:58
+   |
+LL |     let _: for<'a> fn(<() as Foo<T>>::Type<'a>, &'a T) = |_, _| ();
+   |                                                          ^^^^^^^^^
+
+error: aborting due to 8 previous errors
+
index bfe0fc15fd310aa4729b6defec08304a8901180d..377b8164ad506745b26b62cb75d7a72493020614 100644 (file)
@@ -1,5 +1,4 @@
 // edition:2018
-// check-pass
 
 #![feature(generic_associated_types)]
 
@@ -18,6 +17,14 @@ fn call_connect<C>(c: &'_ C) -> impl '_ + Future + Send
     C: Client + Send + Sync,
 {
     async move { c.connect().await }
+    //~^ ERROR `C` does not live long enough
+    //
+    // FIXME(#71723). This is because we infer at some point a value of
+    //
+    // impl Future<Output = <C as Client>::Connection<'_>>
+    //
+    // and then we somehow fail the WF check because `where C: 'a` is not known,
+    // but I'm not entirely sure how that comes about.
 }
 
 fn main() {}
diff --git a/src/test/ui/generic-associated-types/issue-92096.stderr b/src/test/ui/generic-associated-types/issue-92096.stderr
new file mode 100644 (file)
index 0000000..ca61a0f
--- /dev/null
@@ -0,0 +1,8 @@
+error: `C` does not live long enough
+  --> $DIR/issue-92096.rs:19:5
+   |
+LL |     async move { c.connect().await }
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
index b50f56b03d9cd0ecd89fb439617d6ceff6d58987..92b7c5deb812e2946573db4516e454d06b5f8e5d 100644 (file)
@@ -1,10 +1,12 @@
 // Regression test for #88586: a higher-ranked outlives bound on Self in a trait
 // definition caused an ICE when debug_assertions were enabled.
 //
-// FIXME: The error output in the absence of the ICE is unhelpful; this should be improved.
+// Made to pass as part of fixing #98095.
+//
+// check-pass
 
-trait A where for<'a> Self: 'a
-//~^ ERROR the parameter type `Self` may not live long enough
+trait A where
+    for<'a> Self: 'a,
 {
 }
 
diff --git a/src/test/ui/higher-rank-trait-bounds/issue-88586-hr-self-outlives-in-trait-def.stderr b/src/test/ui/higher-rank-trait-bounds/issue-88586-hr-self-outlives-in-trait-def.stderr
deleted file mode 100644 (file)
index 18618ff..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-error[E0311]: the parameter type `Self` may not live long enough
-  --> $DIR/issue-88586-hr-self-outlives-in-trait-def.rs:6:1
-   |
-LL | / trait A where for<'a> Self: 'a
-LL | |
-LL | | {
-LL | | }
-   | |_^
-   |
-   = help: consider adding an explicit lifetime bound `Self: 'a`...
-   = note: ...so that the type `Self` will meet its required lifetime bounds...
-note: ...that is required by this bound
-  --> $DIR/issue-88586-hr-self-outlives-in-trait-def.rs:6:29
-   |
-LL | trait A where for<'a> Self: 'a
-   |                             ^^
-
-error: aborting due to previous error
-
diff --git a/src/test/ui/nll/snocat-regression.rs b/src/test/ui/nll/snocat-regression.rs
new file mode 100644 (file)
index 0000000..b2e5995
--- /dev/null
@@ -0,0 +1,16 @@
+// Regression test from https://github.com/rust-lang/rust/pull/98109
+
+pub fn negotiate<S>(link: S)
+where
+    for<'a> &'a S: 'a,
+{
+    || {
+        //~^ ERROR `S` does not live long enough
+        //
+        // FIXME(#98437). This regressed at some point and
+        // probably should work.
+        let _x = link;
+    };
+}
+
+fn main() {}
diff --git a/src/test/ui/nll/snocat-regression.stderr b/src/test/ui/nll/snocat-regression.stderr
new file mode 100644 (file)
index 0000000..0868984
--- /dev/null
@@ -0,0 +1,14 @@
+error: `S` does not live long enough
+  --> $DIR/snocat-regression.rs:7:5
+   |
+LL | /     || {
+LL | |
+LL | |         //
+LL | |         // FIXME(#98437). This regressed at some point and
+LL | |         // probably should work.
+LL | |         let _x = link;
+LL | |     };
+   | |_____^
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/nll/type-test-universe.rs b/src/test/ui/nll/type-test-universe.rs
new file mode 100644 (file)
index 0000000..f9801c0
--- /dev/null
@@ -0,0 +1,21 @@
+// Regression test for #98095: make sure that
+// we detect that S needs to outlive 'static.
+
+fn outlives_forall<T>()
+where
+    for<'u> T: 'u,
+{
+}
+
+fn test1<S>() {
+    outlives_forall::<S>();
+    //~^ ERROR `S` does not live long enough
+}
+
+struct Value<'a>(&'a ());
+fn test2<'a>() {
+    outlives_forall::<Value<'a>>();
+    //~^ ERROR lifetime may not live long enough
+}
+
+fn main() {}
diff --git a/src/test/ui/nll/type-test-universe.stderr b/src/test/ui/nll/type-test-universe.stderr
new file mode 100644 (file)
index 0000000..242486c
--- /dev/null
@@ -0,0 +1,16 @@
+error: `S` does not live long enough
+  --> $DIR/type-test-universe.rs:11:5
+   |
+LL |     outlives_forall::<S>();
+   |     ^^^^^^^^^^^^^^^^^^^^^^
+
+error: lifetime may not live long enough
+  --> $DIR/type-test-universe.rs:17:5
+   |
+LL | fn test2<'a>() {
+   |          -- lifetime `'a` defined here
+LL |     outlives_forall::<Value<'a>>();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'a` must outlive `'static`
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/ui/nll/vimwiki-core-regression.rs b/src/test/ui/nll/vimwiki-core-regression.rs
new file mode 100644 (file)
index 0000000..0a4ed7e
--- /dev/null
@@ -0,0 +1,37 @@
+// check-pass
+//
+// Regression test from crater run for
+// <https://github.com/rust-lang/rust/pull/98109>.
+
+
+pub trait ElementLike {}
+
+pub struct Located<T> where T: ElementLike {
+    inner: T,
+}
+
+pub struct BlockElement<'a>(&'a str);
+
+impl ElementLike for BlockElement<'_> {}
+
+
+pub struct Page<'a> {
+    /// Comprised of the elements within a page
+    pub elements: Vec<Located<BlockElement<'a>>>,
+}
+
+impl<'a, __IdxT> std::ops::Index<__IdxT> for Page<'a> where
+    Vec<Located<BlockElement<'a>>>: std::ops::Index<__IdxT>
+{
+    type Output =
+        <Vec<Located<BlockElement<'a>>> as
+        std::ops::Index<__IdxT>>::Output;
+
+    #[inline]
+    fn index(&self, idx: __IdxT) -> &Self::Output {
+        <Vec<Located<BlockElement<'a>>> as
+                std::ops::Index<__IdxT>>::index(&self.elements, idx)
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/regions/forall-wf-ref-reflexive.rs b/src/test/ui/regions/forall-wf-ref-reflexive.rs
new file mode 100644 (file)
index 0000000..9c37d72
--- /dev/null
@@ -0,0 +1,18 @@
+// Test that we consider `for<'a> &'a T: 'a` to be sufficient to prove
+// that `for<'a> &'a T: 'a`.
+//
+// FIXME. Except we don't!
+
+#![allow(warnings)]
+
+fn self_wf2<T>()
+where
+    for<'a> &'a T: 'a,
+{
+    self_wf2::<T>();
+    //~^ ERROR `T` does not live long enough
+    //
+    // FIXME. This ought to be accepted, presumably.
+}
+
+fn main() {}
diff --git a/src/test/ui/regions/forall-wf-ref-reflexive.stderr b/src/test/ui/regions/forall-wf-ref-reflexive.stderr
new file mode 100644 (file)
index 0000000..3d059cc
--- /dev/null
@@ -0,0 +1,8 @@
+error: `T` does not live long enough
+  --> $DIR/forall-wf-ref-reflexive.rs:12:5
+   |
+LL |     self_wf2::<T>();
+   |     ^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/regions/forall-wf-reflexive.rs b/src/test/ui/regions/forall-wf-reflexive.rs
new file mode 100644 (file)
index 0000000..8e6b822
--- /dev/null
@@ -0,0 +1,15 @@
+// Test that we consider `for<'a> T: 'a` to be sufficient to prove
+// that `for<'a> T: 'a`.
+//
+// check-pass
+
+#![allow(warnings)]
+
+fn self_wf1<T>()
+where
+    for<'a> T: 'a,
+{
+    self_wf1::<T>();
+}
+
+fn main() {}