Skip to content

Commit e8e32e4

Browse files
committed
Ignore static lifetimes for GATs outlives lint
1 parent e012a19 commit e8e32e4

File tree

2 files changed

+61
-46
lines changed

2 files changed

+61
-46
lines changed

Diff for: compiler/rustc_typeck/src/check/wfcheck.rs

+48-46
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,9 @@ use rustc_hir::lang_items::LangItem;
1414
use rustc_hir::ItemKind;
1515
use rustc_infer::infer::outlives::env::OutlivesEnvironment;
1616
use rustc_infer::infer::outlives::obligations::TypeOutlives;
17-
use rustc_infer::infer::TyCtxtInferExt;
18-
use rustc_infer::infer::{self, RegionckMode, SubregionOrigin};
17+
use rustc_infer::infer::region_constraints::GenericKind;
18+
use rustc_infer::infer::{self, RegionckMode};
19+
use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
1920
use rustc_middle::hir::map as hir_map;
2021
use rustc_middle::ty::subst::{GenericArgKind, InternalSubsts, Subst};
2122
use rustc_middle::ty::trait_def::TraitSpecializationKind;
@@ -332,6 +333,12 @@ fn check_gat_where_clauses(
332333
// outlives relationship (`Self: 'a`), then we want to ensure that is
333334
// reflected in a where clause on the GAT itself.
334335
for (region, region_idx) in &regions {
336+
// Ignore `'static` lifetimes for the purpose of this lint: it's
337+
// because we know it outlives everything and so doesn't give meaninful
338+
// clues
339+
if let ty::ReStatic = region {
340+
continue;
341+
}
335342
for (ty, ty_idx) in &types {
336343
// In our example, requires that Self: 'a
337344
if ty_known_to_outlive(tcx, id, param_env, &wf_tys, *ty, *region) {
@@ -371,10 +378,19 @@ fn check_gat_where_clauses(
371378
// outlives relationship, then we want to ensure that is
372379
// reflected in a where clause on the GAT itself.
373380
for (region_a, region_a_idx) in &regions {
381+
// Ignore `'static` lifetimes for the purpose of this lint: it's
382+
// because we know it outlives everything and so doesn't give meaninful
383+
// clues
384+
if let ty::ReStatic = region_a {
385+
continue;
386+
}
374387
for (region_b, region_b_idx) in &regions {
375388
if region_a == region_b {
376389
continue;
377390
}
391+
if let ty::ReStatic = region_b {
392+
continue;
393+
}
378394

379395
if region_known_to_outlive(tcx, id, param_env, &wf_tys, *region_a, *region_b) {
380396
debug!(?region_a_idx, ?region_b_idx);
@@ -502,8 +518,6 @@ fn check_gat_where_clauses(
502518
}
503519
}
504520

505-
// FIXME(jackh726): refactor some of the shared logic between the two functions below
506-
507521
/// Given a known `param_env` and a set of well formed types, can we prove that
508522
/// `ty` outlives `region`.
509523
fn ty_known_to_outlive<'tcx>(
@@ -514,54 +528,49 @@ fn ty_known_to_outlive<'tcx>(
514528
ty: Ty<'tcx>,
515529
region: ty::Region<'tcx>,
516530
) -> bool {
517-
// Unfortunately, we have to use a new `InferCtxt` each call, because
518-
// region constraints get added and solved there and we need to test each
519-
// call individually.
520-
tcx.infer_ctxt().enter(|infcx| {
521-
let mut outlives_environment = OutlivesEnvironment::new(param_env);
522-
outlives_environment.add_implied_bounds(&infcx, wf_tys.clone(), id, DUMMY_SP);
523-
outlives_environment.save_implied_bounds(id);
524-
let region_bound_pairs = outlives_environment.region_bound_pairs_map().get(&id).unwrap();
525-
526-
let cause = ObligationCause::new(DUMMY_SP, id, ObligationCauseCode::MiscObligation);
527-
528-
let sup_type = ty;
529-
let sub_region = region;
530-
531-
let origin = SubregionOrigin::from_obligation_cause(&cause, || {
532-
infer::RelateParamBound(cause.span, sup_type, None)
533-
});
534-
531+
resolve_regions_with_wf_tys(tcx, id, param_env, &wf_tys, |infcx, region_bound_pairs| {
532+
let origin = infer::RelateParamBound(DUMMY_SP, ty, None);
535533
let outlives = &mut TypeOutlives::new(
536-
&infcx,
534+
infcx,
537535
tcx,
538-
&region_bound_pairs,
536+
region_bound_pairs,
539537
Some(infcx.tcx.lifetimes.re_root_empty),
540538
param_env,
541539
);
542-
outlives.type_must_outlive(origin, sup_type, sub_region);
543-
544-
let errors = infcx.resolve_regions(
545-
id.expect_owner().to_def_id(),
546-
&outlives_environment,
547-
RegionckMode::default(),
548-
);
549-
550-
debug!(?errors, "errors");
551-
552-
// If we were able to prove that the type outlives the region without
553-
// an error, it must be because of the implied or explicit bounds...
554-
errors.is_empty()
540+
outlives.type_must_outlive(origin, ty, region);
555541
})
556542
}
557543

544+
/// Given a known `param_env` and a set of well formed types, can we prove that
545+
/// `region_a` outlives `region_b`
558546
fn region_known_to_outlive<'tcx>(
559547
tcx: TyCtxt<'tcx>,
560548
id: hir::HirId,
561549
param_env: ty::ParamEnv<'tcx>,
562550
wf_tys: &FxHashSet<Ty<'tcx>>,
563551
region_a: ty::Region<'tcx>,
564552
region_b: ty::Region<'tcx>,
553+
) -> bool {
554+
resolve_regions_with_wf_tys(tcx, id, param_env, &wf_tys, |mut infcx, _| {
555+
use rustc_infer::infer::outlives::obligations::TypeOutlivesDelegate;
556+
let origin = infer::RelateRegionParamBound(DUMMY_SP);
557+
// `region_a: region_b` -> `region_b <= region_a`
558+
infcx.push_sub_region_constraint(origin, region_b, region_a);
559+
})
560+
}
561+
562+
/// Given a known `param_env` and a set of well formed types, set up an
563+
/// `InferCtxt`, call the passed function (to e.g. set up region constraints
564+
/// to be tested), then resolve region and return errors
565+
fn resolve_regions_with_wf_tys<'tcx>(
566+
tcx: TyCtxt<'tcx>,
567+
id: hir::HirId,
568+
param_env: ty::ParamEnv<'tcx>,
569+
wf_tys: &FxHashSet<Ty<'tcx>>,
570+
add_constraints: impl for<'a> FnOnce(
571+
&'a InferCtxt<'a, 'tcx>,
572+
&'a Vec<(&'tcx ty::RegionKind, GenericKind<'tcx>)>,
573+
),
565574
) -> bool {
566575
// Unfortunately, we have to use a new `InferCtxt` each call, because
567576
// region constraints get added and solved there and we need to test each
@@ -570,16 +579,9 @@ fn region_known_to_outlive<'tcx>(
570579
let mut outlives_environment = OutlivesEnvironment::new(param_env);
571580
outlives_environment.add_implied_bounds(&infcx, wf_tys.clone(), id, DUMMY_SP);
572581
outlives_environment.save_implied_bounds(id);
582+
let region_bound_pairs = outlives_environment.region_bound_pairs_map().get(&id).unwrap();
573583

574-
let cause = ObligationCause::new(DUMMY_SP, id, ObligationCauseCode::MiscObligation);
575-
576-
let origin = SubregionOrigin::from_obligation_cause(&cause, || {
577-
infer::RelateRegionParamBound(cause.span)
578-
});
579-
580-
use rustc_infer::infer::outlives::obligations::TypeOutlivesDelegate;
581-
// `region_a: region_b` -> `region_b <= region_a`
582-
(&infcx).push_sub_region_constraint(origin, region_b, region_a);
584+
add_constraints(&infcx, region_bound_pairs);
583585

584586
let errors = infcx.resolve_regions(
585587
id.expect_owner().to_def_id(),

Diff for: src/test/ui/generic-associated-types/self-outlives-lint.rs

+13
Original file line numberDiff line numberDiff line change
@@ -189,4 +189,17 @@ trait Trait: 'static {
189189
fn make_assoc(_: &u32) -> Self::Assoc<'_>;
190190
}
191191

192+
// We ignore `'static` lifetimes for any lints
193+
trait StaticReturn<'a> {
194+
type Y<'b>;
195+
fn foo(&self) -> Self::Y<'static>;
196+
}
197+
198+
// Same as above, but with extra method that takes GAT - just make sure this works
199+
trait StaticReturnAndTakes<'a> {
200+
type Y<'b>;
201+
fn foo(&self) -> Self::Y<'static>;
202+
fn bar<'b>(&self, arg: Self::Y<'b>);
203+
}
204+
192205
fn main() {}

0 commit comments

Comments
 (0)