mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-23 07:14:28 +00:00
Rollup merge of #92865 - jackh726:gats-outlives-no-static, r=nikomatsakis
Ignore static lifetimes for GATs outlives lint cc https://github.com/rust-lang/rust/issues/87479#issuecomment-1010484170 Also included a bit of cleanup of `ty_known_to_outlive` and `region_known_to_outlive` r? `@nikomatsakis`
This commit is contained in:
commit
cd93be0094
@ -14,8 +14,9 @@ use rustc_hir::lang_items::LangItem;
|
|||||||
use rustc_hir::ItemKind;
|
use rustc_hir::ItemKind;
|
||||||
use rustc_infer::infer::outlives::env::OutlivesEnvironment;
|
use rustc_infer::infer::outlives::env::OutlivesEnvironment;
|
||||||
use rustc_infer::infer::outlives::obligations::TypeOutlives;
|
use rustc_infer::infer::outlives::obligations::TypeOutlives;
|
||||||
use rustc_infer::infer::TyCtxtInferExt;
|
use rustc_infer::infer::region_constraints::GenericKind;
|
||||||
use rustc_infer::infer::{self, RegionckMode, SubregionOrigin};
|
use rustc_infer::infer::{self, RegionckMode};
|
||||||
|
use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
|
||||||
use rustc_middle::hir::map as hir_map;
|
use rustc_middle::hir::map as hir_map;
|
||||||
use rustc_middle::ty::subst::{GenericArgKind, InternalSubsts, Subst};
|
use rustc_middle::ty::subst::{GenericArgKind, InternalSubsts, Subst};
|
||||||
use rustc_middle::ty::trait_def::TraitSpecializationKind;
|
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
|
// outlives relationship (`Self: 'a`), then we want to ensure that is
|
||||||
// reflected in a where clause on the GAT itself.
|
// reflected in a where clause on the GAT itself.
|
||||||
for (region, region_idx) in ®ions {
|
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 {
|
for (ty, ty_idx) in &types {
|
||||||
// In our example, requires that Self: 'a
|
// In our example, requires that Self: 'a
|
||||||
if ty_known_to_outlive(tcx, id, param_env, &wf_tys, *ty, *region) {
|
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
|
// outlives relationship, then we want to ensure that is
|
||||||
// reflected in a where clause on the GAT itself.
|
// reflected in a where clause on the GAT itself.
|
||||||
for (region_a, region_a_idx) in ®ions {
|
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 {
|
for (region_b, region_b_idx) in ®ions {
|
||||||
if region_a == region_b {
|
if region_a == region_b {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
if let ty::ReStatic = region_b {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if region_known_to_outlive(tcx, id, param_env, &wf_tys, *region_a, *region_b) {
|
if region_known_to_outlive(tcx, id, param_env, &wf_tys, *region_a, *region_b) {
|
||||||
debug!(?region_a_idx, ?region_b_idx);
|
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
|
/// Given a known `param_env` and a set of well formed types, can we prove that
|
||||||
/// `ty` outlives `region`.
|
/// `ty` outlives `region`.
|
||||||
fn ty_known_to_outlive<'tcx>(
|
fn ty_known_to_outlive<'tcx>(
|
||||||
@ -513,6 +527,50 @@ fn ty_known_to_outlive<'tcx>(
|
|||||||
wf_tys: &FxHashSet<Ty<'tcx>>,
|
wf_tys: &FxHashSet<Ty<'tcx>>,
|
||||||
ty: Ty<'tcx>,
|
ty: Ty<'tcx>,
|
||||||
region: ty::Region<'tcx>,
|
region: ty::Region<'tcx>,
|
||||||
|
) -> bool {
|
||||||
|
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,
|
||||||
|
tcx,
|
||||||
|
region_bound_pairs,
|
||||||
|
Some(infcx.tcx.lifetimes.re_root_empty),
|
||||||
|
param_env,
|
||||||
|
);
|
||||||
|
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,
|
||||||
|
param_env: ty::ParamEnv<'tcx>,
|
||||||
|
wf_tys: &FxHashSet<Ty<'tcx>>,
|
||||||
|
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<Ty<'tcx>>,
|
||||||
|
add_constraints: impl for<'a> FnOnce(
|
||||||
|
&'a InferCtxt<'a, 'tcx>,
|
||||||
|
&'a Vec<(&'tcx ty::RegionKind, GenericKind<'tcx>)>,
|
||||||
|
),
|
||||||
) -> bool {
|
) -> bool {
|
||||||
// Unfortunately, we have to use a new `InferCtxt` each call, because
|
// Unfortunately, we have to use a new `InferCtxt` each call, because
|
||||||
// region constraints get added and solved there and we need to test each
|
// region constraints get added and solved there and we need to test each
|
||||||
@ -523,63 +581,7 @@ fn ty_known_to_outlive<'tcx>(
|
|||||||
outlives_environment.save_implied_bounds(id);
|
outlives_environment.save_implied_bounds(id);
|
||||||
let region_bound_pairs = outlives_environment.region_bound_pairs_map().get(&id).unwrap();
|
let region_bound_pairs = outlives_environment.region_bound_pairs_map().get(&id).unwrap();
|
||||||
|
|
||||||
let cause = ObligationCause::new(DUMMY_SP, id, ObligationCauseCode::MiscObligation);
|
add_constraints(&infcx, region_bound_pairs);
|
||||||
|
|
||||||
let sup_type = ty;
|
|
||||||
let sub_region = region;
|
|
||||||
|
|
||||||
let origin = SubregionOrigin::from_obligation_cause(&cause, || {
|
|
||||||
infer::RelateParamBound(cause.span, sup_type, None)
|
|
||||||
});
|
|
||||||
|
|
||||||
let outlives = &mut TypeOutlives::new(
|
|
||||||
&infcx,
|
|
||||||
tcx,
|
|
||||||
®ion_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()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
fn region_known_to_outlive<'tcx>(
|
|
||||||
tcx: TyCtxt<'tcx>,
|
|
||||||
id: hir::HirId,
|
|
||||||
param_env: ty::ParamEnv<'tcx>,
|
|
||||||
wf_tys: &FxHashSet<Ty<'tcx>>,
|
|
||||||
region_a: ty::Region<'tcx>,
|
|
||||||
region_b: 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 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);
|
|
||||||
|
|
||||||
let errors = infcx.resolve_regions(
|
let errors = infcx.resolve_regions(
|
||||||
id.expect_owner().to_def_id(),
|
id.expect_owner().to_def_id(),
|
||||||
|
@ -189,4 +189,17 @@ trait Trait: 'static {
|
|||||||
fn make_assoc(_: &u32) -> Self::Assoc<'_>;
|
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() {}
|
fn main() {}
|
||||||
|
Loading…
Reference in New Issue
Block a user