diff --git a/compiler/rustc_typeck/src/check/wfcheck.rs b/compiler/rustc_typeck/src/check/wfcheck.rs index 7c4f5d16abcab..fbc446e3ea42e 100644 --- a/compiler/rustc_typeck/src/check/wfcheck.rs +++ b/compiler/rustc_typeck/src/check/wfcheck.rs @@ -14,8 +14,9 @@ use rustc_hir::lang_items::LangItem; use rustc_hir::ItemKind; use rustc_infer::infer::outlives::env::OutlivesEnvironment; use rustc_infer::infer::outlives::obligations::TypeOutlives; -use rustc_infer::infer::TyCtxtInferExt; -use rustc_infer::infer::{self, RegionckMode, SubregionOrigin}; +use rustc_infer::infer::region_constraints::GenericKind; +use rustc_infer::infer::{self, RegionckMode}; +use rustc_infer::infer::{InferCtxt, TyCtxtInferExt}; use rustc_middle::hir::map as hir_map; use rustc_middle::ty::subst::{GenericArgKind, InternalSubsts, Subst}; use rustc_middle::ty::trait_def::TraitSpecializationKind; @@ -332,6 +333,12 @@ fn check_gat_where_clauses( // outlives relationship (`Self: 'a`), then we want to ensure that is // reflected in a where clause on the GAT itself. for (region, region_idx) in ®ions { + // Ignore `'static` lifetimes for the purpose of this lint: it's + // because we know it outlives everything and so doesn't give meaninful + // clues + if let ty::ReStatic = region { + continue; + } for (ty, ty_idx) in &types { // In our example, requires that Self: 'a if ty_known_to_outlive(tcx, id, param_env, &wf_tys, *ty, *region) { @@ -371,10 +378,19 @@ fn check_gat_where_clauses( // outlives relationship, then we want to ensure that is // reflected in a where clause on the GAT itself. for (region_a, region_a_idx) in ®ions { + // Ignore `'static` lifetimes for the purpose of this lint: it's + // because we know it outlives everything and so doesn't give meaninful + // clues + if let ty::ReStatic = region_a { + continue; + } for (region_b, region_b_idx) in ®ions { if region_a == region_b { continue; } + if let ty::ReStatic = region_b { + continue; + } if region_known_to_outlive(tcx, id, param_env, &wf_tys, *region_a, *region_b) { debug!(?region_a_idx, ?region_b_idx); @@ -502,8 +518,6 @@ fn check_gat_where_clauses( } } -// FIXME(jackh726): refactor some of the shared logic between the two functions below - /// Given a known `param_env` and a set of well formed types, can we prove that /// `ty` outlives `region`. fn ty_known_to_outlive<'tcx>( @@ -514,47 +528,21 @@ fn ty_known_to_outlive<'tcx>( ty: Ty<'tcx>, region: ty::Region<'tcx>, ) -> bool { - // Unfortunately, we have to use a new `InferCtxt` each call, because - // region constraints get added and solved there and we need to test each - // call individually. - tcx.infer_ctxt().enter(|infcx| { - let mut outlives_environment = OutlivesEnvironment::new(param_env); - outlives_environment.add_implied_bounds(&infcx, wf_tys.clone(), id, DUMMY_SP); - outlives_environment.save_implied_bounds(id); - let region_bound_pairs = outlives_environment.region_bound_pairs_map().get(&id).unwrap(); - - let cause = ObligationCause::new(DUMMY_SP, id, ObligationCauseCode::MiscObligation); - - let sup_type = ty; - let sub_region = region; - - let origin = SubregionOrigin::from_obligation_cause(&cause, || { - infer::RelateParamBound(cause.span, sup_type, None) - }); - + resolve_regions_with_wf_tys(tcx, id, param_env, &wf_tys, |infcx, region_bound_pairs| { + let origin = infer::RelateParamBound(DUMMY_SP, ty, None); let outlives = &mut TypeOutlives::new( - &infcx, + infcx, tcx, - ®ion_bound_pairs, + region_bound_pairs, Some(infcx.tcx.lifetimes.re_root_empty), param_env, ); - outlives.type_must_outlive(origin, sup_type, sub_region); - - let errors = infcx.resolve_regions( - id.expect_owner().to_def_id(), - &outlives_environment, - RegionckMode::default(), - ); - - debug!(?errors, "errors"); - - // If we were able to prove that the type outlives the region without - // an error, it must be because of the implied or explicit bounds... - errors.is_empty() + outlives.type_must_outlive(origin, ty, region); }) } +/// Given a known `param_env` and a set of well formed types, can we prove that +/// `region_a` outlives `region_b` fn region_known_to_outlive<'tcx>( tcx: TyCtxt<'tcx>, id: hir::HirId, @@ -562,6 +550,27 @@ fn region_known_to_outlive<'tcx>( wf_tys: &FxHashSet>, region_a: ty::Region<'tcx>, region_b: ty::Region<'tcx>, +) -> bool { + resolve_regions_with_wf_tys(tcx, id, param_env, &wf_tys, |mut infcx, _| { + use rustc_infer::infer::outlives::obligations::TypeOutlivesDelegate; + let origin = infer::RelateRegionParamBound(DUMMY_SP); + // `region_a: region_b` -> `region_b <= region_a` + infcx.push_sub_region_constraint(origin, region_b, region_a); + }) +} + +/// Given a known `param_env` and a set of well formed types, set up an +/// `InferCtxt`, call the passed function (to e.g. set up region constraints +/// to be tested), then resolve region and return errors +fn resolve_regions_with_wf_tys<'tcx>( + tcx: TyCtxt<'tcx>, + id: hir::HirId, + param_env: ty::ParamEnv<'tcx>, + wf_tys: &FxHashSet>, + add_constraints: impl for<'a> FnOnce( + &'a InferCtxt<'a, 'tcx>, + &'a Vec<(&'tcx ty::RegionKind, GenericKind<'tcx>)>, + ), ) -> bool { // Unfortunately, we have to use a new `InferCtxt` each call, because // region constraints get added and solved there and we need to test each @@ -570,16 +579,9 @@ fn region_known_to_outlive<'tcx>( let mut outlives_environment = OutlivesEnvironment::new(param_env); outlives_environment.add_implied_bounds(&infcx, wf_tys.clone(), id, DUMMY_SP); outlives_environment.save_implied_bounds(id); + let region_bound_pairs = outlives_environment.region_bound_pairs_map().get(&id).unwrap(); - let cause = ObligationCause::new(DUMMY_SP, id, ObligationCauseCode::MiscObligation); - - let origin = SubregionOrigin::from_obligation_cause(&cause, || { - infer::RelateRegionParamBound(cause.span) - }); - - use rustc_infer::infer::outlives::obligations::TypeOutlivesDelegate; - // `region_a: region_b` -> `region_b <= region_a` - (&infcx).push_sub_region_constraint(origin, region_b, region_a); + add_constraints(&infcx, region_bound_pairs); let errors = infcx.resolve_regions( id.expect_owner().to_def_id(), diff --git a/src/test/ui/generic-associated-types/self-outlives-lint.rs b/src/test/ui/generic-associated-types/self-outlives-lint.rs index 37b3a6155d5ae..fcc53b4ede0cb 100644 --- a/src/test/ui/generic-associated-types/self-outlives-lint.rs +++ b/src/test/ui/generic-associated-types/self-outlives-lint.rs @@ -189,4 +189,17 @@ trait Trait: 'static { fn make_assoc(_: &u32) -> Self::Assoc<'_>; } +// We ignore `'static` lifetimes for any lints +trait StaticReturn<'a> { + type Y<'b>; + fn foo(&self) -> Self::Y<'static>; +} + +// Same as above, but with extra method that takes GAT - just make sure this works +trait StaticReturnAndTakes<'a> { + type Y<'b>; + fn foo(&self) -> Self::Y<'static>; + fn bar<'b>(&self, arg: Self::Y<'b>); +} + fn main() {}