diff --git a/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs b/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs index 3f9c0cecccc68..167960918308c 100644 --- a/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs +++ b/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs @@ -22,6 +22,16 @@ pub(crate) struct ConstraintConversion<'a, 'tcx> { infcx: &'a InferCtxt<'a, 'tcx>, tcx: TyCtxt<'tcx>, universal_regions: &'a UniversalRegions<'tcx>, + /// Each RBP `GK: 'a` is assumed to be true. These encode + /// relationships like `T: 'a` that are added via implicit bounds + /// or the `param_env`. + /// + /// Each region here is guaranteed to be a key in the `indices` + /// map. We use the "original" regions (i.e., the keys from the + /// map, and not the values) because the code in + /// `process_registered_region_obligations` has some special-cased + /// logic expecting to see (e.g.) `ReStatic`, and if we supplied + /// our special inference variable there, we would mess that up. region_bound_pairs: &'a RegionBoundPairs<'tcx>, implicit_region_bound: ty::Region<'tcx>, param_env: ty::ParamEnv<'tcx>, diff --git a/compiler/rustc_borrowck/src/type_check/free_region_relations.rs b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs index fe66821ad752b..cc0318ede54a0 100644 --- a/compiler/rustc_borrowck/src/type_check/free_region_relations.rs +++ b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs @@ -2,6 +2,7 @@ use rustc_data_structures::frozen::Frozen; use rustc_data_structures::transitive_relation::TransitiveRelation; use rustc_infer::infer::canonical::QueryRegionConstraints; use rustc_infer::infer::outlives; +use rustc_infer::infer::outlives::env::RegionBoundPairs; use rustc_infer::infer::region_constraints::GenericKind; use rustc_infer::infer::InferCtxt; use rustc_middle::mir::ConstraintCategory; @@ -34,18 +35,6 @@ pub(crate) struct UniversalRegionRelations<'tcx> { inverse_outlives: TransitiveRelation, } -/// Each RBP `('a, GK)` indicates that `GK: 'a` can be assumed to -/// be true. These encode relationships like `T: 'a` that are -/// added via implicit bounds. -/// -/// Each region here is guaranteed to be a key in the `indices` -/// map. We use the "original" regions (i.e., the keys from the -/// map, and not the values) because the code in -/// `process_registered_region_obligations` has some special-cased -/// logic expecting to see (e.g.) `ReStatic`, and if we supplied -/// our special inference variable there, we would mess that up. -type RegionBoundPairs<'tcx> = Vec<(ty::Region<'tcx>, GenericKind<'tcx>)>; - /// As part of computing the free region relations, we also have to /// normalize the input-output types, which we then need later. So we /// return those. This vector consists of first the input types and @@ -71,7 +60,7 @@ pub(crate) fn create<'tcx>( implicit_region_bound, constraints, universal_regions: universal_regions.clone(), - region_bound_pairs: Vec::new(), + region_bound_pairs: Default::default(), relations: UniversalRegionRelations { universal_regions: universal_regions.clone(), outlives: Default::default(), @@ -371,11 +360,13 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> { } OutlivesBound::RegionSubParam(r_a, param_b) => { - self.region_bound_pairs.push((r_a, GenericKind::Param(param_b))); + self.region_bound_pairs + .insert(ty::OutlivesPredicate(GenericKind::Param(param_b), r_a)); } OutlivesBound::RegionSubProjection(r_a, projection_b) => { - self.region_bound_pairs.push((r_a, GenericKind::Projection(projection_b))); + self.region_bound_pairs + .insert(ty::OutlivesPredicate(GenericKind::Projection(projection_b), r_a)); } } } diff --git a/compiler/rustc_infer/src/infer/outlives/env.rs b/compiler/rustc_infer/src/infer/outlives/env.rs index b897de7315a02..b2decd64f0fd9 100644 --- a/compiler/rustc_infer/src/infer/outlives/env.rs +++ b/compiler/rustc_infer/src/infer/outlives/env.rs @@ -1,6 +1,7 @@ use crate::infer::free_regions::FreeRegionMap; use crate::infer::{GenericKind, InferCtxt}; use crate::traits::query::OutlivesBound; +use rustc_data_structures::fx::FxIndexSet; use rustc_middle::ty::{self, ReEarlyBound, ReFree, ReVar, Region}; use super::explicit_outlives_bounds; @@ -53,7 +54,8 @@ pub struct OutlivesEnvironment<'tcx> { /// "Region-bound pairs" tracks outlives relations that are known to /// be true, either because of explicit where-clauses like `T: 'a` or /// because of implied bounds. -pub type RegionBoundPairs<'tcx> = Vec<(Region<'tcx>, GenericKind<'tcx>)>; +pub type RegionBoundPairs<'tcx> = + FxIndexSet, Region<'tcx>>>; impl<'a, 'tcx> OutlivesEnvironment<'tcx> { pub fn new(param_env: ty::ParamEnv<'tcx>) -> Self { @@ -97,10 +99,12 @@ impl<'a, 'tcx> OutlivesEnvironment<'tcx> { debug!("add_outlives_bounds: outlives_bound={:?}", outlives_bound); match outlives_bound { OutlivesBound::RegionSubParam(r_a, param_b) => { - self.region_bound_pairs.push((r_a, GenericKind::Param(param_b))); + self.region_bound_pairs + .insert(ty::OutlivesPredicate(GenericKind::Param(param_b), r_a)); } OutlivesBound::RegionSubProjection(r_a, projection_b) => { - self.region_bound_pairs.push((r_a, GenericKind::Projection(projection_b))); + self.region_bound_pairs + .insert(ty::OutlivesPredicate(GenericKind::Projection(projection_b), r_a)); } OutlivesBound::RegionSubRegion(r_a, r_b) => { if let (ReEarlyBound(_) | ReFree(_), ReVar(vid_b)) = (r_a.kind(), r_b.kind()) { diff --git a/compiler/rustc_infer/src/infer/outlives/verify.rs b/compiler/rustc_infer/src/infer/outlives/verify.rs index faa0a18f93d9a..c7d7ef40d9d41 100644 --- a/compiler/rustc_infer/src/infer/outlives/verify.rs +++ b/compiler/rustc_infer/src/infer/outlives/verify.rs @@ -6,7 +6,7 @@ use rustc_data_structures::captures::Captures; use rustc_data_structures::sso::SsoHashSet; use rustc_hir::def_id::DefId; use rustc_middle::ty::subst::{GenericArg, Subst}; -use rustc_middle::ty::{self, EarlyBinder, Ty, TyCtxt}; +use rustc_middle::ty::{self, EarlyBinder, OutlivesPredicate, Ty, TyCtxt}; use smallvec::smallvec; @@ -259,16 +259,17 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> { // The problem is that the type of `x` is `&'a A`. To be // well-formed, then, A must outlive `'a`, but we don't know that // this holds from first principles. - let from_region_bound_pairs = self.region_bound_pairs.iter().filter_map(|&(r, p)| { - debug!( - "declared_generic_bounds_from_env_for_erased_ty: region_bound_pair = {:?}", - (r, p) - ); - let p_ty = p.to_ty(tcx); - let erased_p_ty = self.tcx.erase_regions(p_ty); - (erased_p_ty == erased_ty) - .then_some(ty::Binder::dummy(ty::OutlivesPredicate(p.to_ty(tcx), r))) - }); + let from_region_bound_pairs = + self.region_bound_pairs.iter().filter_map(|&OutlivesPredicate(p, r)| { + debug!( + "declared_generic_bounds_from_env_for_erased_ty: region_bound_pair = {:?}", + (r, p) + ); + let p_ty = p.to_ty(tcx); + let erased_p_ty = self.tcx.erase_regions(p_ty); + (erased_p_ty == erased_ty) + .then_some(ty::Binder::dummy(ty::OutlivesPredicate(p.to_ty(tcx), r))) + }); param_bounds .chain(from_region_bound_pairs) diff --git a/compiler/rustc_typeck/src/check/wfcheck.rs b/compiler/rustc_typeck/src/check/wfcheck.rs index bae986de9a23d..faab862cc3c3c 100644 --- a/compiler/rustc_typeck/src/check/wfcheck.rs +++ b/compiler/rustc_typeck/src/check/wfcheck.rs @@ -7,9 +7,8 @@ use rustc_hir as hir; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::lang_items::LangItem; use rustc_hir::ItemKind; -use rustc_infer::infer::outlives::env::OutlivesEnvironment; +use rustc_infer::infer::outlives::env::{OutlivesEnvironment, RegionBoundPairs}; use rustc_infer::infer::outlives::obligations::TypeOutlives; -use rustc_infer::infer::region_constraints::GenericKind; use rustc_infer::infer::{self, InferCtxt, TyCtxtInferExt}; use rustc_infer::traits::Normalized; use rustc_middle::ty::query::Providers; @@ -689,10 +688,7 @@ fn resolve_regions_with_wf_tys<'tcx>( id: hir::HirId, param_env: ty::ParamEnv<'tcx>, wf_tys: &FxHashSet>, - add_constraints: impl for<'a> FnOnce( - &'a InferCtxt<'a, 'tcx>, - &'a Vec<(ty::Region<'tcx>, GenericKind<'tcx>)>, - ), + add_constraints: impl for<'a> FnOnce(&'a InferCtxt<'a, 'tcx>, &'a RegionBoundPairs<'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