Skip to content
This repository was archived by the owner on May 28, 2025. It is now read-only.
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit d017d59

Browse files
committedJun 24, 2022
Auto merge of rust-lang#98109 - nikomatsakis:issue-98095, r=jackh726
fix universes in the NLL type tests In the NLL code, we were not accommodating universes in the `type_test` logic. Fixes rust-lang#98095. r? `@compiler-errors` This breaks some tests, however, so the purpose of this branch is more explanatory and perhaps to do a crater run.
2 parents fc96600 + e7ed8fe commit d017d59

29 files changed

+735
-267
lines changed
 

‎compiler/rustc_borrowck/src/nll.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -299,7 +299,7 @@ pub(crate) fn compute_regions<'cx, 'tcx>(
299299

300300
// Solve the region constraints.
301301
let (closure_region_requirements, nll_errors) =
302-
regioncx.solve(infcx, &body, polonius_output.clone());
302+
regioncx.solve(infcx, param_env, &body, polonius_output.clone());
303303

304304
if !nll_errors.is_empty() {
305305
// Suppress unhelpful extra errors in `infer_opaque_types`.

‎compiler/rustc_borrowck/src/region_infer/mod.rs

Lines changed: 81 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@ use rustc_hir::def_id::{DefId, CRATE_DEF_ID};
1010
use rustc_hir::CRATE_HIR_ID;
1111
use rustc_index::vec::IndexVec;
1212
use rustc_infer::infer::canonical::QueryOutlivesConstraint;
13-
use rustc_infer::infer::region_constraints::{GenericKind, VarInfos, VerifyBound};
13+
use rustc_infer::infer::outlives::test_type_match;
14+
use rustc_infer::infer::region_constraints::{GenericKind, VarInfos, VerifyBound, VerifyIfEq};
1415
use rustc_infer::infer::{InferCtxt, NllRegionVariableOrigin, RegionVariableOrigin};
1516
use rustc_middle::mir::{
1617
Body, ClosureOutlivesRequirement, ClosureOutlivesSubject, ClosureRegionRequirements,
@@ -46,6 +47,7 @@ pub mod values;
4647

4748
pub struct RegionInferenceContext<'tcx> {
4849
pub var_infos: VarInfos,
50+
4951
/// Contains the definition for every region variable. Region
5052
/// variables are identified by their index (`RegionVid`). The
5153
/// definition contains information about where the region came
@@ -559,6 +561,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
559561
pub(super) fn solve(
560562
&mut self,
561563
infcx: &InferCtxt<'_, 'tcx>,
564+
param_env: ty::ParamEnv<'tcx>,
562565
body: &Body<'tcx>,
563566
polonius_output: Option<Rc<PoloniusOutput>>,
564567
) -> (Option<ClosureRegionRequirements<'tcx>>, RegionErrors<'tcx>) {
@@ -574,7 +577,13 @@ impl<'tcx> RegionInferenceContext<'tcx> {
574577
// eagerly.
575578
let mut outlives_requirements = infcx.tcx.is_typeck_child(mir_def_id).then(Vec::new);
576579

577-
self.check_type_tests(infcx, body, outlives_requirements.as_mut(), &mut errors_buffer);
580+
self.check_type_tests(
581+
infcx,
582+
param_env,
583+
body,
584+
outlives_requirements.as_mut(),
585+
&mut errors_buffer,
586+
);
578587

579588
// In Polonius mode, the errors about missing universal region relations are in the output
580589
// and need to be emitted or propagated. Otherwise, we need to check whether the
@@ -823,6 +832,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
823832
fn check_type_tests(
824833
&self,
825834
infcx: &InferCtxt<'_, 'tcx>,
835+
param_env: ty::ParamEnv<'tcx>,
826836
body: &Body<'tcx>,
827837
mut propagated_outlives_requirements: Option<&mut Vec<ClosureOutlivesRequirement<'tcx>>>,
828838
errors_buffer: &mut RegionErrors<'tcx>,
@@ -839,7 +849,8 @@ impl<'tcx> RegionInferenceContext<'tcx> {
839849

840850
let generic_ty = type_test.generic_kind.to_ty(tcx);
841851
if self.eval_verify_bound(
842-
tcx,
852+
infcx,
853+
param_env,
843854
body,
844855
generic_ty,
845856
type_test.lower_bound,
@@ -851,6 +862,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
851862
if let Some(propagated_outlives_requirements) = &mut propagated_outlives_requirements {
852863
if self.try_promote_type_test(
853864
infcx,
865+
param_env,
854866
body,
855867
type_test,
856868
propagated_outlives_requirements,
@@ -907,6 +919,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
907919
fn try_promote_type_test(
908920
&self,
909921
infcx: &InferCtxt<'_, 'tcx>,
922+
param_env: ty::ParamEnv<'tcx>,
910923
body: &Body<'tcx>,
911924
type_test: &TypeTest<'tcx>,
912925
propagated_outlives_requirements: &mut Vec<ClosureOutlivesRequirement<'tcx>>,
@@ -938,7 +951,14 @@ impl<'tcx> RegionInferenceContext<'tcx> {
938951
// where `ur` is a local bound -- we are sometimes in a
939952
// position to prove things that our caller cannot. See
940953
// #53570 for an example.
941-
if self.eval_verify_bound(tcx, body, generic_ty, ur, &type_test.verify_bound) {
954+
if self.eval_verify_bound(
955+
infcx,
956+
param_env,
957+
body,
958+
generic_ty,
959+
ur,
960+
&type_test.verify_bound,
961+
) {
942962
continue;
943963
}
944964

@@ -1161,7 +1181,8 @@ impl<'tcx> RegionInferenceContext<'tcx> {
11611181
/// `point`.
11621182
fn eval_verify_bound(
11631183
&self,
1164-
tcx: TyCtxt<'tcx>,
1184+
infcx: &InferCtxt<'_, 'tcx>,
1185+
param_env: ty::ParamEnv<'tcx>,
11651186
body: &Body<'tcx>,
11661187
generic_ty: Ty<'tcx>,
11671188
lower_bound: RegionVid,
@@ -1170,8 +1191,8 @@ impl<'tcx> RegionInferenceContext<'tcx> {
11701191
debug!("eval_verify_bound(lower_bound={:?}, verify_bound={:?})", lower_bound, verify_bound);
11711192

11721193
match verify_bound {
1173-
VerifyBound::IfEq(test_ty, verify_bound1) => {
1174-
self.eval_if_eq(tcx, body, generic_ty, lower_bound, *test_ty, verify_bound1)
1194+
VerifyBound::IfEq(verify_if_eq_b) => {
1195+
self.eval_if_eq(infcx, param_env, generic_ty, lower_bound, *verify_if_eq_b)
11751196
}
11761197

11771198
VerifyBound::IsEmpty => {
@@ -1185,30 +1206,50 @@ impl<'tcx> RegionInferenceContext<'tcx> {
11851206
}
11861207

11871208
VerifyBound::AnyBound(verify_bounds) => verify_bounds.iter().any(|verify_bound| {
1188-
self.eval_verify_bound(tcx, body, generic_ty, lower_bound, verify_bound)
1209+
self.eval_verify_bound(
1210+
infcx,
1211+
param_env,
1212+
body,
1213+
generic_ty,
1214+
lower_bound,
1215+
verify_bound,
1216+
)
11891217
}),
11901218

11911219
VerifyBound::AllBounds(verify_bounds) => verify_bounds.iter().all(|verify_bound| {
1192-
self.eval_verify_bound(tcx, body, generic_ty, lower_bound, verify_bound)
1220+
self.eval_verify_bound(
1221+
infcx,
1222+
param_env,
1223+
body,
1224+
generic_ty,
1225+
lower_bound,
1226+
verify_bound,
1227+
)
11931228
}),
11941229
}
11951230
}
11961231

11971232
fn eval_if_eq(
11981233
&self,
1199-
tcx: TyCtxt<'tcx>,
1200-
body: &Body<'tcx>,
1234+
infcx: &InferCtxt<'_, 'tcx>,
1235+
param_env: ty::ParamEnv<'tcx>,
12011236
generic_ty: Ty<'tcx>,
12021237
lower_bound: RegionVid,
1203-
test_ty: Ty<'tcx>,
1204-
verify_bound: &VerifyBound<'tcx>,
1238+
verify_if_eq_b: ty::Binder<'tcx, VerifyIfEq<'tcx>>,
12051239
) -> bool {
1206-
let generic_ty_normalized = self.normalize_to_scc_representatives(tcx, generic_ty);
1207-
let test_ty_normalized = self.normalize_to_scc_representatives(tcx, test_ty);
1208-
if generic_ty_normalized == test_ty_normalized {
1209-
self.eval_verify_bound(tcx, body, generic_ty, lower_bound, verify_bound)
1210-
} else {
1211-
false
1240+
let generic_ty = self.normalize_to_scc_representatives(infcx.tcx, generic_ty);
1241+
let verify_if_eq_b = self.normalize_to_scc_representatives(infcx.tcx, verify_if_eq_b);
1242+
match test_type_match::extract_verify_if_eq(
1243+
infcx.tcx,
1244+
param_env,
1245+
&verify_if_eq_b,
1246+
generic_ty,
1247+
) {
1248+
Some(r) => {
1249+
let r_vid = self.to_region_vid(r);
1250+
self.eval_outlives(r_vid, lower_bound)
1251+
}
1252+
None => false,
12121253
}
12131254
}
12141255

@@ -1278,6 +1319,18 @@ impl<'tcx> RegionInferenceContext<'tcx> {
12781319
let sub_region_scc = self.constraint_sccs.scc(sub_region);
12791320
let sup_region_scc = self.constraint_sccs.scc(sup_region);
12801321

1322+
// If we are checking that `'sup: 'sub`, and `'sub` contains
1323+
// some placeholder that `'sup` cannot name, then this is only
1324+
// true if `'sup` outlives static.
1325+
if !self.universe_compatible(sub_region_scc, sup_region_scc) {
1326+
debug!(
1327+
"eval_outlives: sub universe `{sub_region_scc:?}` is not nameable \
1328+
by super `{sup_region_scc:?}`, promoting to static",
1329+
);
1330+
1331+
return self.eval_outlives(sup_region, self.universal_regions.fr_static);
1332+
}
1333+
12811334
// Both the `sub_region` and `sup_region` consist of the union
12821335
// of some number of universal regions (along with the union
12831336
// of various points in the CFG; ignore those points for
@@ -1292,6 +1345,9 @@ impl<'tcx> RegionInferenceContext<'tcx> {
12921345
});
12931346

12941347
if !universal_outlives {
1348+
debug!(
1349+
"eval_outlives: returning false because sub region contains a universal region not present in super"
1350+
);
12951351
return false;
12961352
}
12971353

@@ -1300,10 +1356,15 @@ impl<'tcx> RegionInferenceContext<'tcx> {
13001356

13011357
if self.universal_regions.is_universal_region(sup_region) {
13021358
// Micro-opt: universal regions contain all points.
1359+
debug!(
1360+
"eval_outlives: returning true because super is universal and hence contains all points"
1361+
);
13031362
return true;
13041363
}
13051364

1306-
self.scc_values.contains_points(sup_region_scc, sub_region_scc)
1365+
let result = self.scc_values.contains_points(sup_region_scc, sub_region_scc);
1366+
debug!("returning {} because of comparison between points in sup/sub", result);
1367+
result
13071368
}
13081369

13091370
/// Once regions have been propagated, this method is used to see

‎compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,19 +22,22 @@ use rustc_middle::ty::{Region, RegionVid};
2222
use rustc_span::Span;
2323
use std::fmt;
2424

25+
use super::outlives::test_type_match;
26+
2527
/// This function performs lexical region resolution given a complete
2628
/// set of constraints and variable origins. It performs a fixed-point
2729
/// iteration to find region values which satisfy all constraints,
2830
/// assuming such values can be found. It returns the final values of
2931
/// all the variables as well as a set of errors that must be reported.
3032
#[instrument(level = "debug", skip(region_rels, var_infos, data))]
3133
pub(crate) fn resolve<'tcx>(
34+
param_env: ty::ParamEnv<'tcx>,
3235
region_rels: &RegionRelations<'_, 'tcx>,
3336
var_infos: VarInfos,
3437
data: RegionConstraintData<'tcx>,
3538
) -> (LexicalRegionResolutions<'tcx>, Vec<RegionResolutionError<'tcx>>) {
3639
let mut errors = vec![];
37-
let mut resolver = LexicalResolver { region_rels, var_infos, data };
40+
let mut resolver = LexicalResolver { param_env, region_rels, var_infos, data };
3841
let values = resolver.infer_variable_values(&mut errors);
3942
(values, errors)
4043
}
@@ -100,6 +103,7 @@ struct RegionAndOrigin<'tcx> {
100103
type RegionGraph<'tcx> = Graph<(), Constraint<'tcx>>;
101104

102105
struct LexicalResolver<'cx, 'tcx> {
106+
param_env: ty::ParamEnv<'tcx>,
103107
region_rels: &'cx RegionRelations<'cx, 'tcx>,
104108
var_infos: VarInfos,
105109
data: RegionConstraintData<'tcx>,
@@ -818,9 +822,20 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
818822
min: ty::Region<'tcx>,
819823
) -> bool {
820824
match bound {
821-
VerifyBound::IfEq(k, b) => {
822-
(var_values.normalize(self.region_rels.tcx, *k) == generic_ty)
823-
&& self.bound_is_met(b, var_values, generic_ty, min)
825+
VerifyBound::IfEq(verify_if_eq_b) => {
826+
let verify_if_eq_b = var_values.normalize(self.region_rels.tcx, *verify_if_eq_b);
827+
match test_type_match::extract_verify_if_eq(
828+
self.tcx(),
829+
self.param_env,
830+
&verify_if_eq_b,
831+
generic_ty,
832+
) {
833+
Some(r) => {
834+
self.bound_is_met(&VerifyBound::OutlivedBy(r), var_values, generic_ty, min)
835+
}
836+
837+
None => false,
838+
}
824839
}
825840

826841
VerifyBound::OutlivedBy(r) => {

‎compiler/rustc_infer/src/infer/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1290,7 +1290,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
12901290
&RegionRelations::new(self.tcx, region_context, outlives_env.free_region_map());
12911291

12921292
let (lexical_region_resolutions, errors) =
1293-
lexical_region_resolve::resolve(region_rels, var_infos, data);
1293+
lexical_region_resolve::resolve(outlives_env.param_env, region_rels, var_infos, data);
12941294

12951295
let old_value = self.lexical_region_resolutions.replace(Some(lexical_region_resolutions));
12961296
assert!(old_value.is_none());

‎compiler/rustc_infer/src/infer/outlives/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
pub mod components;
44
pub mod env;
55
pub mod obligations;
6+
pub mod test_type_match;
67
pub mod verify;
78

89
use rustc_middle::traits::query::OutlivesBound;

‎compiler/rustc_infer/src/infer/outlives/obligations.rs

Lines changed: 27 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -318,17 +318,13 @@ where
318318
self.delegate.push_verify(origin, generic, region, verify_bound);
319319
}
320320

321+
#[tracing::instrument(level = "debug", skip(self))]
321322
fn projection_must_outlive(
322323
&mut self,
323324
origin: infer::SubregionOrigin<'tcx>,
324325
region: ty::Region<'tcx>,
325326
projection_ty: ty::ProjectionTy<'tcx>,
326327
) {
327-
debug!(
328-
"projection_must_outlive(region={:?}, projection_ty={:?}, origin={:?})",
329-
region, projection_ty, origin
330-
);
331-
332328
// This case is thorny for inference. The fundamental problem is
333329
// that there are many cases where we have choice, and inference
334330
// doesn't like choice (the current region inference in
@@ -363,13 +359,21 @@ where
363359
// #55756) in cases where you have e.g., `<T as Foo<'a>>::Item:
364360
// 'a` in the environment but `trait Foo<'b> { type Item: 'b
365361
// }` in the trait definition.
366-
approx_env_bounds.retain(|bound| match *bound.0.kind() {
367-
ty::Projection(projection_ty) => self
368-
.verify_bound
369-
.projection_declared_bounds_from_trait(projection_ty)
370-
.all(|r| r != bound.1),
371-
372-
_ => panic!("expected only projection types from env, not {:?}", bound.0),
362+
approx_env_bounds.retain(|bound_outlives| {
363+
// OK to skip binder because we only manipulate and compare against other
364+
// values from the same binder. e.g. if we have (e.g.) `for<'a> <T as Trait<'a>>::Item: 'a`
365+
// in `bound`, the `'a` will be a `^1` (bound, debruijn index == innermost) region.
366+
// If the declaration is `trait Trait<'b> { type Item: 'b; }`, then `projection_declared_bounds_from_trait`
367+
// will be invoked with `['b => ^1]` and so we will get `^1` returned.
368+
let bound = bound_outlives.skip_binder();
369+
match *bound.0.kind() {
370+
ty::Projection(projection_ty) => self
371+
.verify_bound
372+
.projection_declared_bounds_from_trait(projection_ty)
373+
.all(|r| r != bound.1),
374+
375+
_ => panic!("expected only projection types from env, not {:?}", bound.0),
376+
}
373377
});
374378

375379
// If declared bounds list is empty, the only applicable rule is
@@ -420,8 +424,16 @@ where
420424
if !trait_bounds.is_empty()
421425
&& trait_bounds[1..]
422426
.iter()
423-
.chain(approx_env_bounds.iter().map(|b| &b.1))
424-
.all(|b| *b == trait_bounds[0])
427+
.map(|r| Some(*r))
428+
.chain(
429+
// NB: The environment may contain `for<'a> T: 'a` style bounds.
430+
// In that case, we don't know if they are equal to the trait bound
431+
// or not (since we don't *know* whether the environment bound even applies),
432+
// so just map to `None` here if there are bound vars, ensuring that
433+
// the call to `all` will fail below.
434+
approx_env_bounds.iter().map(|b| b.map_bound(|b| b.1).no_bound_vars()),
435+
)
436+
.all(|b| b == Some(trait_bounds[0]))
425437
{
426438
let unique_bound = trait_bounds[0];
427439
debug!("projection_must_outlive: unique trait bound = {:?}", unique_bound);
@@ -437,6 +449,7 @@ where
437449
// even though a satisfactory solution exists.
438450
let generic = GenericKind::Projection(projection_ty);
439451
let verify_bound = self.verify_bound.generic_bound(generic);
452+
debug!("projection_must_outlive: pushing {:?}", verify_bound);
440453
self.delegate.push_verify(origin, generic, region, verify_bound);
441454
}
442455
}
Lines changed: 207 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,207 @@
1+
use std::collections::hash_map::Entry;
2+
3+
use rustc_data_structures::fx::FxHashMap;
4+
use rustc_middle::ty::TypeFoldable;
5+
use rustc_middle::ty::{
6+
self,
7+
error::TypeError,
8+
relate::{self, Relate, RelateResult, TypeRelation},
9+
Ty, TyCtxt,
10+
};
11+
12+
use crate::infer::region_constraints::VerifyIfEq;
13+
14+
/// Given a "verify-if-eq" type test like:
15+
///
16+
/// exists<'a...> {
17+
/// verify_if_eq(some_type, bound_region)
18+
/// }
19+
///
20+
/// and the type `test_ty` that the type test is being tested against,
21+
/// returns:
22+
///
23+
/// * `None` if `some_type` cannot be made equal to `test_ty`,
24+
/// no matter the values of the variables in `exists`.
25+
/// * `Some(r)` with a suitable bound (typically the value of `bound_region`, modulo
26+
/// any bound existential variables, which will be substituted) for the
27+
/// type under test.
28+
///
29+
/// NB: This function uses a simplistic, syntactic version of type equality.
30+
/// In other words, it may spuriously return `None` even if the type-under-test
31+
/// is in fact equal to `some_type`. In practice, though, this is used on types
32+
/// that are either projections like `T::Item` or `T` and it works fine, but it
33+
/// could have trouble when complex types with higher-ranked binders and the
34+
/// like are used. This is a particular challenge since this function is invoked
35+
/// very late in inference and hence cannot make use of the normal inference
36+
/// machinery.
37+
#[tracing::instrument(level = "debug", skip(tcx, param_env))]
38+
pub fn extract_verify_if_eq<'tcx>(
39+
tcx: TyCtxt<'tcx>,
40+
param_env: ty::ParamEnv<'tcx>,
41+
verify_if_eq_b: &ty::Binder<'tcx, VerifyIfEq<'tcx>>,
42+
test_ty: Ty<'tcx>,
43+
) -> Option<ty::Region<'tcx>> {
44+
assert!(!verify_if_eq_b.has_escaping_bound_vars());
45+
let mut m = Match::new(tcx, param_env);
46+
let verify_if_eq = verify_if_eq_b.skip_binder();
47+
m.relate(verify_if_eq.ty, test_ty).ok()?;
48+
49+
if let ty::RegionKind::ReLateBound(depth, br) = verify_if_eq.bound.kind() {
50+
assert!(depth == ty::INNERMOST);
51+
match m.map.get(&br) {
52+
Some(&r) => Some(r),
53+
None => {
54+
// If there is no mapping, then this region is unconstrained.
55+
// In that case, we escalate to `'static`.
56+
Some(tcx.lifetimes.re_static)
57+
}
58+
}
59+
} else {
60+
// The region does not contain any bound variables, so we don't need
61+
// to do any substitution.
62+
//
63+
// Example:
64+
//
65+
// for<'a> <T as Foo<'a>>::Item: 'b
66+
//
67+
// In this case, we've now matched and found a value for
68+
// `'a`, but it doesn't affect the bound `'b`.
69+
Some(verify_if_eq.bound)
70+
}
71+
}
72+
73+
/// True if a (potentially higher-ranked) outlives
74+
#[tracing::instrument(level = "debug", skip(tcx, param_env))]
75+
pub(super) fn can_match_erased_ty<'tcx>(
76+
tcx: TyCtxt<'tcx>,
77+
param_env: ty::ParamEnv<'tcx>,
78+
outlives_predicate: ty::Binder<'tcx, ty::TypeOutlivesPredicate<'tcx>>,
79+
erased_ty: Ty<'tcx>,
80+
) -> bool {
81+
assert!(!outlives_predicate.has_escaping_bound_vars());
82+
let erased_outlives_predicate = tcx.erase_regions(outlives_predicate);
83+
let outlives_ty = erased_outlives_predicate.skip_binder().0;
84+
if outlives_ty == erased_ty {
85+
// pointless micro-optimization
86+
true
87+
} else {
88+
Match::new(tcx, param_env).relate(outlives_ty, erased_ty).is_ok()
89+
}
90+
}
91+
92+
struct Match<'tcx> {
93+
tcx: TyCtxt<'tcx>,
94+
param_env: ty::ParamEnv<'tcx>,
95+
pattern_depth: ty::DebruijnIndex,
96+
map: FxHashMap<ty::BoundRegion, ty::Region<'tcx>>,
97+
}
98+
99+
impl<'tcx> Match<'tcx> {
100+
fn new(tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> Match<'tcx> {
101+
Match { tcx, param_env, pattern_depth: ty::INNERMOST, map: FxHashMap::default() }
102+
}
103+
}
104+
105+
impl<'tcx> Match<'tcx> {
106+
/// Creates the "Error" variant that signals "no match".
107+
fn no_match<T>(&self) -> RelateResult<'tcx, T> {
108+
Err(TypeError::Mismatch)
109+
}
110+
111+
/// Binds the pattern variable `br` to `value`; returns an `Err` if the pattern
112+
/// is already bound to a different value.
113+
#[tracing::instrument(level = "debug", skip(self))]
114+
fn bind(
115+
&mut self,
116+
br: ty::BoundRegion,
117+
value: ty::Region<'tcx>,
118+
) -> RelateResult<'tcx, ty::Region<'tcx>> {
119+
match self.map.entry(br) {
120+
Entry::Occupied(entry) => {
121+
if *entry.get() == value {
122+
Ok(value)
123+
} else {
124+
self.no_match()
125+
}
126+
}
127+
Entry::Vacant(entry) => {
128+
entry.insert(value);
129+
Ok(value)
130+
}
131+
}
132+
}
133+
}
134+
135+
impl<'tcx> TypeRelation<'tcx> for Match<'tcx> {
136+
fn tag(&self) -> &'static str {
137+
"Match"
138+
}
139+
fn tcx(&self) -> TyCtxt<'tcx> {
140+
self.tcx
141+
}
142+
fn param_env(&self) -> ty::ParamEnv<'tcx> {
143+
self.param_env
144+
}
145+
fn a_is_expected(&self) -> bool {
146+
true
147+
} // irrelevant
148+
149+
fn relate_with_variance<T: Relate<'tcx>>(
150+
&mut self,
151+
_: ty::Variance,
152+
_: ty::VarianceDiagInfo<'tcx>,
153+
a: T,
154+
b: T,
155+
) -> RelateResult<'tcx, T> {
156+
self.relate(a, b)
157+
}
158+
159+
#[instrument(skip(self), level = "debug")]
160+
fn regions(
161+
&mut self,
162+
pattern: ty::Region<'tcx>,
163+
value: ty::Region<'tcx>,
164+
) -> RelateResult<'tcx, ty::Region<'tcx>> {
165+
debug!("self.pattern_depth = {:?}", self.pattern_depth);
166+
if let ty::RegionKind::ReLateBound(depth, br) = pattern.kind() && depth == self.pattern_depth {
167+
self.bind(br, value)
168+
} else if pattern == value {
169+
Ok(pattern)
170+
} else {
171+
self.no_match()
172+
}
173+
}
174+
175+
#[instrument(skip(self), level = "debug")]
176+
fn tys(&mut self, pattern: Ty<'tcx>, value: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
177+
if pattern == value { Ok(pattern) } else { relate::super_relate_tys(self, pattern, value) }
178+
}
179+
180+
#[instrument(skip(self), level = "debug")]
181+
fn consts(
182+
&mut self,
183+
pattern: ty::Const<'tcx>,
184+
value: ty::Const<'tcx>,
185+
) -> RelateResult<'tcx, ty::Const<'tcx>> {
186+
debug!("{}.consts({:?}, {:?})", self.tag(), pattern, value);
187+
if pattern == value {
188+
Ok(pattern)
189+
} else {
190+
relate::super_relate_consts(self, pattern, value)
191+
}
192+
}
193+
194+
fn binders<T>(
195+
&mut self,
196+
pattern: ty::Binder<'tcx, T>,
197+
value: ty::Binder<'tcx, T>,
198+
) -> RelateResult<'tcx, ty::Binder<'tcx, T>>
199+
where
200+
T: Relate<'tcx>,
201+
{
202+
self.pattern_depth.shift_in(1);
203+
let result = Ok(pattern.rebind(self.relate(pattern.skip_binder(), value.skip_binder())?));
204+
self.pattern_depth.shift_out(1);
205+
result
206+
}
207+
}

‎compiler/rustc_infer/src/infer/outlives/verify.rs

Lines changed: 68 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use crate::infer::outlives::env::RegionBoundPairs;
2+
use crate::infer::region_constraints::VerifyIfEq;
23
use crate::infer::{GenericKind, VerifyBound};
34
use rustc_data_structures::captures::Captures;
45
use rustc_data_structures::sso::SsoHashSet;
@@ -82,27 +83,39 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> {
8283
debug!("param_bound(param_ty={:?})", param_ty);
8384

8485
// Start with anything like `T: 'a` we can scrape from the
85-
// environment
86-
let param_bounds = self
87-
.declared_generic_bounds_from_env(GenericKind::Param(param_ty))
88-
.into_iter()
89-
.map(|outlives| outlives.1);
86+
// environment. If the environment contains something like
87+
// `for<'a> T: 'a`, then we know that `T` outlives everything.
88+
let declared_bounds_from_env = self.declared_generic_bounds_from_env(param_ty);
89+
let mut param_bounds = vec![];
90+
for declared_bound in declared_bounds_from_env {
91+
let bound_region = declared_bound.map_bound(|outlives| outlives.1);
92+
if let Some(region) = bound_region.no_bound_vars() {
93+
// This is `T: 'a` for some free region `'a`.
94+
param_bounds.push(VerifyBound::OutlivedBy(region));
95+
} else {
96+
// This is `for<'a> T: 'a`. This means that `T` outlives everything! All done here.
97+
return VerifyBound::AllBounds(vec![]);
98+
}
99+
}
90100

91101
// Add in the default bound of fn body that applies to all in
92102
// scope type parameters:
93-
let param_bounds = param_bounds.chain(self.implicit_region_bound);
94-
95-
let any_bounds: Vec<_> = param_bounds.map(|r| VerifyBound::OutlivedBy(r)).collect();
103+
if let Some(r) = self.implicit_region_bound {
104+
param_bounds.push(VerifyBound::OutlivedBy(r));
105+
}
96106

97-
if any_bounds.is_empty() {
107+
if param_bounds.is_empty() {
98108
// We know that all types `T` outlive `'empty`, so if we
99109
// can find no other bound, then check that the region
100110
// being tested is `'empty`.
101111
VerifyBound::IsEmpty
112+
} else if param_bounds.len() == 1 {
113+
// Micro-opt: no need to store the vector if it's just len 1
114+
param_bounds.pop().unwrap()
102115
} else {
103116
// If we can find any other bound `R` such that `T: R`, then
104117
// we don't need to check for `'empty`, because `R: 'empty`.
105-
VerifyBound::AnyBound(any_bounds)
118+
VerifyBound::AnyBound(param_bounds)
106119
}
107120
}
108121

@@ -122,17 +135,10 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> {
122135
pub fn projection_approx_declared_bounds_from_env(
123136
&self,
124137
projection_ty: ty::ProjectionTy<'tcx>,
125-
) -> Vec<ty::OutlivesPredicate<Ty<'tcx>, ty::Region<'tcx>>> {
138+
) -> Vec<ty::Binder<'tcx, ty::OutlivesPredicate<Ty<'tcx>, ty::Region<'tcx>>>> {
126139
let projection_ty = GenericKind::Projection(projection_ty).to_ty(self.tcx);
127140
let erased_projection_ty = self.tcx.erase_regions(projection_ty);
128-
self.declared_generic_bounds_from_env_with_compare_fn(|ty| {
129-
if let ty::Projection(..) = ty.kind() {
130-
let erased_ty = self.tcx.erase_regions(ty);
131-
erased_ty == erased_projection_ty
132-
} else {
133-
false
134-
}
135-
})
141+
self.declared_generic_bounds_from_env_for_erased_ty(erased_projection_ty)
136142
}
137143

138144
/// Searches the where-clauses in scope for regions that
@@ -159,15 +165,15 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> {
159165
let env_bounds = self
160166
.projection_approx_declared_bounds_from_env(projection_ty)
161167
.into_iter()
162-
.map(|ty::OutlivesPredicate(ty, r)| {
163-
let vb = VerifyBound::OutlivedBy(r);
164-
if ty == projection_ty_as_ty {
168+
.map(|binder| {
169+
if let Some(ty::OutlivesPredicate(ty, r)) = binder.no_bound_vars() && ty == projection_ty_as_ty {
165170
// Micro-optimize if this is an exact match (this
166171
// occurs often when there are no region variables
167172
// involved).
168-
vb
173+
VerifyBound::OutlivedBy(r)
169174
} else {
170-
VerifyBound::IfEq(ty, Box::new(vb))
175+
let verify_if_eq_b = binder.map_bound(|ty::OutlivesPredicate(ty, bound)| VerifyIfEq { ty, bound });
176+
VerifyBound::IfEq(verify_if_eq_b)
171177
}
172178
});
173179

@@ -219,26 +225,34 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> {
219225
/// bounds, but all the bounds it returns can be relied upon.
220226
fn declared_generic_bounds_from_env(
221227
&self,
222-
generic: GenericKind<'tcx>,
223-
) -> Vec<ty::OutlivesPredicate<Ty<'tcx>, ty::Region<'tcx>>> {
224-
let generic_ty = generic.to_ty(self.tcx);
225-
self.declared_generic_bounds_from_env_with_compare_fn(|ty| ty == generic_ty)
228+
param_ty: ty::ParamTy,
229+
) -> Vec<ty::Binder<'tcx, ty::OutlivesPredicate<Ty<'tcx>, ty::Region<'tcx>>>> {
230+
let generic_ty = param_ty.to_ty(self.tcx);
231+
self.declared_generic_bounds_from_env_for_erased_ty(generic_ty)
226232
}
227233

228-
fn declared_generic_bounds_from_env_with_compare_fn(
234+
/// Searches the environment to find all bounds that apply to `erased_ty`.
235+
/// Obviously these must be approximate -- they are in fact both *over* and
236+
/// and *under* approximated:
237+
///
238+
/// * Over-approximated because we erase regions, so
239+
/// * Under-approximated because we look for syntactic equality and so for complex types
240+
/// like `<T as Foo<fn(&u32, &u32)>>::Item` or whatever we may fail to figure out
241+
/// all the subtleties.
242+
///
243+
/// In some cases, such as when `erased_ty` represents a `ty::Param`, however,
244+
/// the result is precise.
245+
fn declared_generic_bounds_from_env_for_erased_ty(
229246
&self,
230-
compare_ty: impl Fn(Ty<'tcx>) -> bool,
231-
) -> Vec<ty::OutlivesPredicate<Ty<'tcx>, ty::Region<'tcx>>> {
247+
erased_ty: Ty<'tcx>,
248+
) -> Vec<ty::Binder<'tcx, ty::OutlivesPredicate<Ty<'tcx>, ty::Region<'tcx>>>> {
232249
let tcx = self.tcx;
233250

234251
// To start, collect bounds from user environment. Note that
235252
// parameter environments are already elaborated, so we don't
236-
// have to worry about that. Comparing using `==` is a bit
237-
// dubious for projections, but it will work for simple cases
238-
// like `T` and `T::Item`. It may not work as well for things
239-
// like `<T as Foo<'a>>::Item`.
253+
// have to worry about that.
240254
let c_b = self.param_env.caller_bounds();
241-
let param_bounds = self.collect_outlives_from_predicate_list(&compare_ty, c_b.into_iter());
255+
let param_bounds = self.collect_outlives_from_predicate_list(erased_ty, c_b.into_iter());
242256

243257
// Next, collect regions we scraped from the well-formedness
244258
// constraints in the fn signature. To do that, we walk the list
@@ -253,18 +267,20 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> {
253267
// don't know that this holds from first principles.
254268
let from_region_bound_pairs = self.region_bound_pairs.iter().filter_map(|&(r, p)| {
255269
debug!(
256-
"declared_generic_bounds_from_env_with_compare_fn: region_bound_pair = {:?}",
270+
"declared_generic_bounds_from_env_for_erased_ty: region_bound_pair = {:?}",
257271
(r, p)
258272
);
259273
let p_ty = p.to_ty(tcx);
260-
compare_ty(p_ty).then_some(ty::OutlivesPredicate(p_ty, r))
274+
let erased_p_ty = self.tcx.erase_regions(p_ty);
275+
(erased_p_ty == erased_ty)
276+
.then_some(ty::Binder::dummy(ty::OutlivesPredicate(p.to_ty(tcx), r)))
261277
});
262278

263279
param_bounds
264280
.chain(from_region_bound_pairs)
265281
.inspect(|bound| {
266282
debug!(
267-
"declared_generic_bounds_from_env_with_compare_fn: result predicate = {:?}",
283+
"declared_generic_bounds_from_env_for_erased_ty: result predicate = {:?}",
268284
bound
269285
)
270286
})
@@ -344,12 +360,19 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> {
344360
/// otherwise want a precise match.
345361
fn collect_outlives_from_predicate_list(
346362
&self,
347-
compare_ty: impl Fn(Ty<'tcx>) -> bool,
363+
erased_ty: Ty<'tcx>,
348364
predicates: impl Iterator<Item = ty::Predicate<'tcx>>,
349-
) -> impl Iterator<Item = ty::OutlivesPredicate<Ty<'tcx>, ty::Region<'tcx>>> {
350-
predicates
351-
.filter_map(|p| p.to_opt_type_outlives())
352-
.filter_map(|p| p.no_bound_vars())
353-
.filter(move |p| compare_ty(p.0))
365+
) -> impl Iterator<Item = ty::Binder<'tcx, ty::OutlivesPredicate<Ty<'tcx>, ty::Region<'tcx>>>>
366+
{
367+
let tcx = self.tcx;
368+
let param_env = self.param_env;
369+
predicates.filter_map(|p| p.to_opt_type_outlives()).filter(move |outlives_predicate| {
370+
super::test_type_match::can_match_erased_ty(
371+
tcx,
372+
param_env,
373+
*outlives_predicate,
374+
erased_ty,
375+
)
376+
})
354377
}
355378
}

‎compiler/rustc_infer/src/infer/region_constraints/mod.rs

Lines changed: 50 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -190,41 +190,8 @@ pub enum GenericKind<'tcx> {
190190
/// This is described with an `AnyRegion('a, 'b)` node.
191191
#[derive(Debug, Clone)]
192192
pub enum VerifyBound<'tcx> {
193-
/// Given a kind K and a bound B, expands to a function like the
194-
/// following, where `G` is the generic for which this verify
195-
/// bound was created:
196-
///
197-
/// ```ignore (pseudo-rust)
198-
/// fn(min) -> bool {
199-
/// if G == K {
200-
/// B(min)
201-
/// } else {
202-
/// false
203-
/// }
204-
/// }
205-
/// ```
206-
///
207-
/// In other words, if the generic `G` that we are checking is
208-
/// equal to `K`, then check the associated verify bound
209-
/// (otherwise, false).
210-
///
211-
/// This is used when we have something in the environment that
212-
/// may or may not be relevant, depending on the region inference
213-
/// results. For example, we may have `where <T as
214-
/// Trait<'a>>::Item: 'b` in our where-clauses. If we are
215-
/// generating the verify-bound for `<T as Trait<'0>>::Item`, then
216-
/// this where-clause is only relevant if `'0` winds up inferred
217-
/// to `'a`.
218-
///
219-
/// So we would compile to a verify-bound like
220-
///
221-
/// ```ignore (illustrative)
222-
/// IfEq(<T as Trait<'a>>::Item, AnyRegion('a))
223-
/// ```
224-
///
225-
/// meaning, if the subject G is equal to `<T as Trait<'a>>::Item`
226-
/// (after inference), and `'a: min`, then `G: min`.
227-
IfEq(Ty<'tcx>, Box<VerifyBound<'tcx>>),
193+
/// See [`VerifyIfEq`] docs
194+
IfEq(ty::Binder<'tcx, VerifyIfEq<'tcx>>),
228195

229196
/// Given a region `R`, expands to the function:
230197
///
@@ -267,6 +234,53 @@ pub enum VerifyBound<'tcx> {
267234
AllBounds(Vec<VerifyBound<'tcx>>),
268235
}
269236

237+
/// This is a "conditional bound" that checks the result of inference
238+
/// and supplies a bound if it ended up being relevant. It's used in situations
239+
/// like this:
240+
///
241+
/// ```rust
242+
/// fn foo<'a, 'b, T: SomeTrait<'a>>
243+
/// where
244+
/// <T as SomeTrait<'a>>::Item: 'b
245+
/// ```
246+
///
247+
/// If we have an obligation like `<T as SomeTrait<'?x>>::Item: 'c`, then
248+
/// we don't know yet whether it suffices to show that `'b: 'c`. If `'?x` winds
249+
/// up being equal to `'a`, then the where-clauses on function applies, and
250+
/// in that case we can show `'b: 'c`. But if `'?x` winds up being something
251+
/// else, the bound isn't relevant.
252+
///
253+
/// In the [`VerifyBound`], this struct is enclosed in `Binder to account
254+
/// for cases like
255+
///
256+
/// ```rust
257+
/// where for<'a> <T as SomeTrait<'a>::Item: 'a
258+
/// ```
259+
///
260+
/// The idea is that we have to find some instantiation of `'a` that can
261+
/// make `<T as SomeTrait<'a>>::Item` equal to the final value of `G`,
262+
/// the generic we are checking.
263+
///
264+
/// ```ignore (pseudo-rust)
265+
/// fn(min) -> bool {
266+
/// exists<'a> {
267+
/// if G == K {
268+
/// B(min)
269+
/// } else {
270+
/// false
271+
/// }
272+
/// }
273+
/// }
274+
/// ```
275+
#[derive(Debug, Copy, Clone, TypeFoldable)]
276+
pub struct VerifyIfEq<'tcx> {
277+
/// Type which must match the generic `G`
278+
pub ty: Ty<'tcx>,
279+
280+
/// Bound that applies if `ty` is equal.
281+
pub bound: Region<'tcx>,
282+
}
283+
270284
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
271285
pub(crate) struct TwoRegions<'tcx> {
272286
a: Region<'tcx>,
@@ -770,7 +784,7 @@ impl<'tcx> VerifyBound<'tcx> {
770784

771785
pub fn cannot_hold(&self) -> bool {
772786
match self {
773-
VerifyBound::IfEq(_, b) => b.cannot_hold(),
787+
VerifyBound::IfEq(..) => false,
774788
VerifyBound::IsEmpty => false,
775789
VerifyBound::OutlivedBy(_) => false,
776790
VerifyBound::AnyBound(bs) => bs.iter().all(|b| b.cannot_hold()),

‎src/test/ui/borrowck/issue-71546.rs

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,16 @@
11
// Regression test for #71546.
2+
//
3+
// Made to pass as part of fixing #98095.
4+
//
5+
// check-pass
26

37
pub fn serialize_as_csv<V>(value: &V) -> Result<String, &str>
48
where
59
V: 'static,
610
for<'a> &'a V: IntoIterator,
711
for<'a> <&'a V as IntoIterator>::Item: ToString + 'static,
812
{
9-
let csv_str: String = value
10-
//~^ ERROR higher-ranked lifetime error
11-
//~| ERROR higher-ranked lifetime error
12-
//~| ERROR higher-ranked lifetime error
13-
.into_iter()
14-
.map(|elem| elem.to_string())
15-
//~^ ERROR higher-ranked lifetime error
16-
.collect::<String>();
17-
//~^ ERROR higher-ranked lifetime error
13+
let csv_str: String = value.into_iter().map(|elem| elem.to_string()).collect::<String>();
1814
Ok(csv_str)
1915
}
2016

‎src/test/ui/borrowck/issue-71546.stderr

Lines changed: 0 additions & 59 deletions
This file was deleted.
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
// Regression test from https://github.com/rust-lang/rust/pull/98109
2+
3+
#![feature(generic_associated_types)]
4+
5+
pub trait Get {
6+
type Value<'a>
7+
where
8+
Self: 'a;
9+
}
10+
11+
fn multiply_at<T>(x: T)
12+
where
13+
for<'a> T: Get<Value<'a> = ()>,
14+
{
15+
|| {
16+
//~^ `T` does not live long enough
17+
//
18+
// FIXME(#98437). This regressed at some point and
19+
// probably should work.
20+
let _x = x;
21+
};
22+
}
23+
24+
fn main() {}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
error: `T` does not live long enough
2+
--> $DIR/collectivity-regression.rs:15:5
3+
|
4+
LL | / || {
5+
LL | |
6+
LL | | //
7+
LL | | // FIXME(#98437). This regressed at some point and
8+
LL | | // probably should work.
9+
LL | | let _x = x;
10+
LL | | };
11+
| |_____^
12+
13+
error: aborting due to previous error
14+
Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,16 @@
11
// Regression test of #86483.
2+
//
3+
// Made to pass as part of fixing #98095.
4+
//
5+
// check-pass
26

37
#![feature(generic_associated_types)]
48

5-
pub trait IceIce<T> //~ ERROR: the parameter type `T` may not live long enough
9+
pub trait IceIce<T>
610
where
711
for<'a> T: 'a,
812
{
913
type Ice<'v>: IntoIterator<Item = &'v T>;
10-
//~^ ERROR: the parameter type `T` may not live long enough
11-
//~| ERROR: the parameter type `T` may not live long enough
1214
}
1315

1416
fn main() {}

‎src/test/ui/generic-associated-types/issue-86483.stderr

Lines changed: 0 additions & 50 deletions
This file was deleted.

‎src/test/ui/generic-associated-types/issue-91139.rs

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
//check-pass
2-
31
#![feature(generic_associated_types)]
42

53
trait Foo<T> {
@@ -16,6 +14,22 @@ impl<T> Foo<T> for () {
1614

1715
fn foo<T>() {
1816
let _: for<'a> fn(<() as Foo<T>>::Type<'a>, &'a T) = |_, _| ();
17+
//~^ ERROR `T` does not live long enough
18+
//~| ERROR `T` does not live long enough
19+
//~| ERROR `T` does not live long enough
20+
//~| ERROR `T` does not live long enough
21+
//~| ERROR `T` does not live long enough
22+
//~| ERROR `T` does not live long enough
23+
//~| ERROR `T` does not live long enough
24+
//~| ERROR `T` does not live long enough
25+
//
26+
// FIXME: This error is bogus, but it arises because we try to validate
27+
// that `<() as Foo<T>>::Type<'a>` is valid, which requires proving
28+
// that `T: 'a`. Since `'a` is higher-ranked, this becomes
29+
// `for<'a> T: 'a`, which is not true. Of course, the error is bogus
30+
// because there *ought* to be an implied bound stating that `'a` is
31+
// not any lifetime but specifically
32+
// "some `'a` such that `<() as Foo<T>>::Type<'a>" is valid".
1933
}
2034

2135
pub fn main() {}
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
error: `T` does not live long enough
2+
--> $DIR/issue-91139.rs:16:12
3+
|
4+
LL | let _: for<'a> fn(<() as Foo<T>>::Type<'a>, &'a T) = |_, _| ();
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
6+
7+
error: `T` does not live long enough
8+
--> $DIR/issue-91139.rs:16:12
9+
|
10+
LL | let _: for<'a> fn(<() as Foo<T>>::Type<'a>, &'a T) = |_, _| ();
11+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
12+
13+
error: `T` does not live long enough
14+
--> $DIR/issue-91139.rs:16:12
15+
|
16+
LL | let _: for<'a> fn(<() as Foo<T>>::Type<'a>, &'a T) = |_, _| ();
17+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
18+
19+
error: `T` does not live long enough
20+
--> $DIR/issue-91139.rs:16:12
21+
|
22+
LL | let _: for<'a> fn(<() as Foo<T>>::Type<'a>, &'a T) = |_, _| ();
23+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
24+
25+
error: `T` does not live long enough
26+
--> $DIR/issue-91139.rs:16:58
27+
|
28+
LL | let _: for<'a> fn(<() as Foo<T>>::Type<'a>, &'a T) = |_, _| ();
29+
| ^^^^^^^^^
30+
31+
error: `T` does not live long enough
32+
--> $DIR/issue-91139.rs:16:58
33+
|
34+
LL | let _: for<'a> fn(<() as Foo<T>>::Type<'a>, &'a T) = |_, _| ();
35+
| ^^^^^^^^^
36+
37+
error: `T` does not live long enough
38+
--> $DIR/issue-91139.rs:16:58
39+
|
40+
LL | let _: for<'a> fn(<() as Foo<T>>::Type<'a>, &'a T) = |_, _| ();
41+
| ^^^^^^^^^
42+
43+
error: `T` does not live long enough
44+
--> $DIR/issue-91139.rs:16:58
45+
|
46+
LL | let _: for<'a> fn(<() as Foo<T>>::Type<'a>, &'a T) = |_, _| ();
47+
| ^^^^^^^^^
48+
49+
error: aborting due to 8 previous errors
50+

‎src/test/ui/generic-associated-types/issue-92096.rs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
// edition:2018
2-
// check-pass
32

43
#![feature(generic_associated_types)]
54

@@ -18,6 +17,14 @@ where
1817
C: Client + Send + Sync,
1918
{
2019
async move { c.connect().await }
20+
//~^ ERROR `C` does not live long enough
21+
//
22+
// FIXME(#71723). This is because we infer at some point a value of
23+
//
24+
// impl Future<Output = <C as Client>::Connection<'_>>
25+
//
26+
// and then we somehow fail the WF check because `where C: 'a` is not known,
27+
// but I'm not entirely sure how that comes about.
2128
}
2229

2330
fn main() {}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
error: `C` does not live long enough
2+
--> $DIR/issue-92096.rs:19:5
3+
|
4+
LL | async move { c.connect().await }
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
6+
7+
error: aborting due to previous error
8+

‎src/test/ui/higher-rank-trait-bounds/issue-88586-hr-self-outlives-in-trait-def.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
// Regression test for #88586: a higher-ranked outlives bound on Self in a trait
22
// definition caused an ICE when debug_assertions were enabled.
33
//
4-
// FIXME: The error output in the absence of the ICE is unhelpful; this should be improved.
4+
// Made to pass as part of fixing #98095.
5+
//
6+
// check-pass
57

6-
trait A where for<'a> Self: 'a
7-
//~^ ERROR the parameter type `Self` may not live long enough
8+
trait A where
9+
for<'a> Self: 'a,
810
{
911
}
1012

‎src/test/ui/higher-rank-trait-bounds/issue-88586-hr-self-outlives-in-trait-def.stderr

Lines changed: 0 additions & 19 deletions
This file was deleted.

‎src/test/ui/nll/snocat-regression.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// Regression test from https://github.com/rust-lang/rust/pull/98109
2+
3+
pub fn negotiate<S>(link: S)
4+
where
5+
for<'a> &'a S: 'a,
6+
{
7+
|| {
8+
//~^ ERROR `S` does not live long enough
9+
//
10+
// FIXME(#98437). This regressed at some point and
11+
// probably should work.
12+
let _x = link;
13+
};
14+
}
15+
16+
fn main() {}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
error: `S` does not live long enough
2+
--> $DIR/snocat-regression.rs:7:5
3+
|
4+
LL | / || {
5+
LL | |
6+
LL | | //
7+
LL | | // FIXME(#98437). This regressed at some point and
8+
LL | | // probably should work.
9+
LL | | let _x = link;
10+
LL | | };
11+
| |_____^
12+
13+
error: aborting due to previous error
14+

‎src/test/ui/nll/type-test-universe.rs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// Regression test for #98095: make sure that
2+
// we detect that S needs to outlive 'static.
3+
4+
fn outlives_forall<T>()
5+
where
6+
for<'u> T: 'u,
7+
{
8+
}
9+
10+
fn test1<S>() {
11+
outlives_forall::<S>();
12+
//~^ ERROR `S` does not live long enough
13+
}
14+
15+
struct Value<'a>(&'a ());
16+
fn test2<'a>() {
17+
outlives_forall::<Value<'a>>();
18+
//~^ ERROR lifetime may not live long enough
19+
}
20+
21+
fn main() {}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
error: `S` does not live long enough
2+
--> $DIR/type-test-universe.rs:11:5
3+
|
4+
LL | outlives_forall::<S>();
5+
| ^^^^^^^^^^^^^^^^^^^^^^
6+
7+
error: lifetime may not live long enough
8+
--> $DIR/type-test-universe.rs:17:5
9+
|
10+
LL | fn test2<'a>() {
11+
| -- lifetime `'a` defined here
12+
LL | outlives_forall::<Value<'a>>();
13+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'a` must outlive `'static`
14+
15+
error: aborting due to 2 previous errors
16+
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
// check-pass
2+
//
3+
// Regression test from crater run for
4+
// <https://github.com/rust-lang/rust/pull/98109>.
5+
6+
7+
pub trait ElementLike {}
8+
9+
pub struct Located<T> where T: ElementLike {
10+
inner: T,
11+
}
12+
13+
pub struct BlockElement<'a>(&'a str);
14+
15+
impl ElementLike for BlockElement<'_> {}
16+
17+
18+
pub struct Page<'a> {
19+
/// Comprised of the elements within a page
20+
pub elements: Vec<Located<BlockElement<'a>>>,
21+
}
22+
23+
impl<'a, __IdxT> std::ops::Index<__IdxT> for Page<'a> where
24+
Vec<Located<BlockElement<'a>>>: std::ops::Index<__IdxT>
25+
{
26+
type Output =
27+
<Vec<Located<BlockElement<'a>>> as
28+
std::ops::Index<__IdxT>>::Output;
29+
30+
#[inline]
31+
fn index(&self, idx: __IdxT) -> &Self::Output {
32+
<Vec<Located<BlockElement<'a>>> as
33+
std::ops::Index<__IdxT>>::index(&self.elements, idx)
34+
}
35+
}
36+
37+
fn main() {}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// Test that we consider `for<'a> &'a T: 'a` to be sufficient to prove
2+
// that `for<'a> &'a T: 'a`.
3+
//
4+
// FIXME. Except we don't!
5+
6+
#![allow(warnings)]
7+
8+
fn self_wf2<T>()
9+
where
10+
for<'a> &'a T: 'a,
11+
{
12+
self_wf2::<T>();
13+
//~^ ERROR `T` does not live long enough
14+
//
15+
// FIXME. This ought to be accepted, presumably.
16+
}
17+
18+
fn main() {}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
error: `T` does not live long enough
2+
--> $DIR/forall-wf-ref-reflexive.rs:12:5
3+
|
4+
LL | self_wf2::<T>();
5+
| ^^^^^^^^^^^^^^^
6+
7+
error: aborting due to previous error
8+
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// Test that we consider `for<'a> T: 'a` to be sufficient to prove
2+
// that `for<'a> T: 'a`.
3+
//
4+
// check-pass
5+
6+
#![allow(warnings)]
7+
8+
fn self_wf1<T>()
9+
where
10+
for<'a> T: 'a,
11+
{
12+
self_wf1::<T>();
13+
}
14+
15+
fn main() {}

0 commit comments

Comments
 (0)
This repository has been archived.