Skip to content

Commit 18421b1

Browse files
committed
Add lint for region pairs too
1 parent b84044a commit 18421b1

File tree

2 files changed

+78
-1
lines changed

2 files changed

+78
-1
lines changed

compiler/rustc_typeck/src/check/wfcheck.rs

+69
Original file line numberDiff line numberDiff line change
@@ -412,6 +412,75 @@ fn check_gat_where_clauses(
412412
}
413413
}
414414

415+
// For each region argument (e.g., 'a in our example), also check for a
416+
// relationship to the other region arguments. If there is an
417+
// outlives relationship, then we want to ensure that is
418+
// reflected in a where clause on the GAT itself.
419+
for (region_a, region_a_idx) in &visitor.regions {
420+
for (region_b, region_b_idx) in &visitor.regions {
421+
if region_a == region_b {
422+
continue;
423+
}
424+
425+
// Unfortunately, we have to use a new `InferCtxt` for each
426+
// pair, because region constraints get added and solved there,
427+
// and we need to test each pair individually.
428+
tcx.infer_ctxt().enter(|infcx| {
429+
let mut outlives_environment = OutlivesEnvironment::new(param_env);
430+
outlives_environment.add_implied_bounds(&infcx, wf_tys.clone(), id, DUMMY_SP);
431+
outlives_environment.save_implied_bounds(id);
432+
433+
let cause =
434+
ObligationCause::new(DUMMY_SP, id, ObligationCauseCode::MiscObligation);
435+
436+
let origin = SubregionOrigin::from_obligation_cause(&cause, || {
437+
infer::RelateRegionParamBound(cause.span)
438+
});
439+
440+
use rustc_infer::infer::outlives::obligations::TypeOutlivesDelegate;
441+
(&infcx).push_sub_region_constraint(origin, region_a, region_b);
442+
443+
let errors = infcx.resolve_regions(
444+
trait_item.def_id.to_def_id(),
445+
&outlives_environment,
446+
RegionckMode::default(),
447+
);
448+
449+
debug!(?errors, "errors");
450+
451+
// If we were able to prove that Self: 'a without an error,
452+
// it must be because of the implied or explicit bounds...
453+
if errors.is_empty() {
454+
debug!(?region_a_idx, ?region_b_idx);
455+
debug!("required clause: {} must outlive {}", region_a, region_b);
456+
// Translate into the generic parameters of the GAT.
457+
let region_a_param = generics.param_at(*region_a_idx, tcx);
458+
let region_a_param =
459+
tcx.mk_region(ty::RegionKind::ReEarlyBound(ty::EarlyBoundRegion {
460+
def_id: region_a_param.def_id,
461+
index: region_a_param.index,
462+
name: region_a_param.name,
463+
}));
464+
// Same for the region.
465+
let region_b_param = generics.param_at(*region_b_idx, tcx);
466+
let region_b_param =
467+
tcx.mk_region(ty::RegionKind::ReEarlyBound(ty::EarlyBoundRegion {
468+
def_id: region_b_param.def_id,
469+
index: region_b_param.index,
470+
name: region_b_param.name,
471+
}));
472+
// The predicate we expect to see.
473+
let clause = ty::PredicateKind::RegionOutlives(ty::OutlivesPredicate(
474+
region_a_param,
475+
region_b_param,
476+
));
477+
let clause = tcx.mk_predicate(ty::Binder::dummy(clause));
478+
function_clauses.insert(clause);
479+
}
480+
});
481+
}
482+
}
483+
415484
match clauses.as_mut() {
416485
Some(clauses) => {
417486
clauses.drain_filter(|p| !function_clauses.contains(p));

src/test/ui/generic-associated-types/self-outlives-lint.stderr

+9-1
Original file line numberDiff line numberDiff line change
@@ -86,5 +86,13 @@ LL | type Iterator<'a>: Iterator<Item = Self::Item<'a>>;
8686
| |
8787
| help: add the required where clauses: `where Self: 'a`
8888

89-
error: aborting due to 11 previous errors
89+
error: Missing required bounds on Bar
90+
--> $DIR/self-outlives-lint.rs:148:5
91+
|
92+
LL | type Bar<'a, 'b>;
93+
| ^^^^^^^^^^^^^^^^-
94+
| |
95+
| help: add the required where clauses: `where 'a: 'b`
96+
97+
error: aborting due to 12 previous errors
9098

0 commit comments

Comments
 (0)