1
Fork 0

Overhaul RegionKind and Region.

Specifically, change `Region` from this:
```
pub type Region<'tcx> = &'tcx RegionKind;
```
to this:
```
pub struct Region<'tcx>(&'tcx Interned<RegionKind>);
```

This now matches `Ty` and `Predicate` more closely.

Things to note
- Regions have always been interned, but we haven't been using pointer-based
  `Eq` and `Hash`. This is now happening.
- I chose to impl `Deref` for `Region` because it makes pattern matching a lot
  nicer, and `Region` can be viewed as just a smart wrapper for `RegionKind`.
- Various methods are moved from `RegionKind` to `Region`.
- There is a lot of tedious sigil changes.
- A couple of types like `HighlightBuilder`, `RegionHighlightMode` now have a
  `'tcx` lifetime because they hold a `Ty<'tcx>`, so they can call `mk_region`.
- A couple of test outputs change slightly, I'm not sure why, but the new
  outputs are a little better.
This commit is contained in:
Nicholas Nethercote 2022-01-28 11:25:15 +11:00
parent 925ec0d3c7
commit 7024dc523a
80 changed files with 443 additions and 346 deletions

View file

@ -194,7 +194,7 @@ macro_rules! make_mir_visitor {
}
fn visit_region(&mut self,
region: & $($mutability)? ty::Region<'tcx>,
region: $(& $mutability)? ty::Region<'tcx>,
_: Location) {
self.super_region(region);
}
@ -641,7 +641,7 @@ macro_rules! make_mir_visitor {
Rvalue::ThreadLocalRef(_) => {}
Rvalue::Ref(r, bk, path) => {
self.visit_region(r, location);
self.visit_region($(& $mutability)? *r, location);
let ctx = match bk {
BorrowKind::Shared => PlaceContext::NonMutatingUse(
NonMutatingUseContext::SharedBorrow
@ -900,7 +900,7 @@ macro_rules! make_mir_visitor {
fn super_ty(&mut self, _ty: $(& $mutability)? Ty<'tcx>) {
}
fn super_region(&mut self, _region: & $($mutability)? ty::Region<'tcx>) {
fn super_region(&mut self, _region: $(& $mutability)? ty::Region<'tcx>) {
}
fn super_const(&mut self, _const: & $($mutability)? &'tcx ty::Const<'tcx>) {

View file

@ -138,6 +138,12 @@ impl<'tcx, E: TyEncoder<'tcx>> Encodable<E> for ty::Predicate<'tcx> {
}
}
impl<'tcx, E: TyEncoder<'tcx>> Encodable<E> for ty::Region<'tcx> {
fn encode(&self, e: &mut E) -> Result<(), E::Error> {
self.kind().encode(e)
}
}
impl<'tcx, E: TyEncoder<'tcx>> Encodable<E> for AllocId {
fn encode(&self, e: &mut E) -> Result<(), E::Error> {
e.encode_alloc_id(self)
@ -156,7 +162,6 @@ macro_rules! encodable_via_deref {
encodable_via_deref! {
&'tcx ty::TypeckResults<'tcx>,
ty::Region<'tcx>,
&'tcx traits::ImplSource<'tcx, ()>,
&'tcx mir::Body<'tcx>,
&'tcx mir::UnsafetyCheckResult,

View file

@ -860,10 +860,10 @@ impl<'tcx> CanonicalUserType<'tcx> {
_ => false,
},
GenericArgKind::Lifetime(r) => match r {
GenericArgKind::Lifetime(r) => match *r {
ty::ReLateBound(debruijn, br) => {
// We only allow a `ty::INNERMOST` index in substitutions.
assert_eq!(*debruijn, ty::INNERMOST);
assert_eq!(debruijn, ty::INNERMOST);
cvar == br.var
}
_ => false,
@ -930,7 +930,11 @@ impl<'tcx> CommonTypes<'tcx> {
impl<'tcx> CommonLifetimes<'tcx> {
fn new(interners: &CtxtInterners<'tcx>) -> CommonLifetimes<'tcx> {
let mk = |r| interners.region.intern(r, |r| InternedInSet(interners.arena.alloc(r))).0;
let mk = |r| {
Region(Interned::new_unchecked(
interners.region.intern(r, |r| InternedInSet(interners.arena.alloc(r))).0,
))
};
CommonLifetimes {
re_root_empty: mk(RegionKind::ReEmpty(ty::UniverseIndex::ROOT)),
@ -1680,7 +1684,7 @@ macro_rules! nop_list_lift {
}
nop_lift! {type_; Ty<'a> => Ty<'tcx>}
nop_lift_old! {region; Region<'a> => Region<'tcx>}
nop_lift! {region; Region<'a> => Region<'tcx>}
nop_lift_old! {const_; &'a Const<'a> => &'tcx Const<'tcx>}
nop_lift_old! {const_allocation; &'a Allocation => &'tcx Allocation}
nop_lift! {predicate; Predicate<'a> => Predicate<'tcx>}
@ -2086,6 +2090,46 @@ impl<'tcx, T: Hash> Hash for InternedInSet<'tcx, List<T>> {
}
macro_rules! direct_interners {
($($name:ident: $method:ident($ty:ty): $ret_ctor:ident -> $ret_ty:ty,)+) => {
$(impl<'tcx> Borrow<$ty> for InternedInSet<'tcx, $ty> {
fn borrow<'a>(&'a self) -> &'a $ty {
&self.0
}
}
impl<'tcx> PartialEq for InternedInSet<'tcx, $ty> {
fn eq(&self, other: &Self) -> bool {
// The `Borrow` trait requires that `x.borrow() == y.borrow()`
// equals `x == y`.
self.0 == other.0
}
}
impl<'tcx> Eq for InternedInSet<'tcx, $ty> {}
impl<'tcx> Hash for InternedInSet<'tcx, $ty> {
fn hash<H: Hasher>(&self, s: &mut H) {
// The `Borrow` trait requires that `x.borrow().hash(s) ==
// x.hash(s)`.
self.0.hash(s)
}
}
impl<'tcx> TyCtxt<'tcx> {
pub fn $method(self, v: $ty) -> $ret_ty {
$ret_ctor(Interned::new_unchecked(self.interners.$name.intern(v, |v| {
InternedInSet(self.interners.arena.alloc(v))
}).0))
}
})+
}
}
direct_interners! {
region: mk_region(RegionKind): Region -> Region<'tcx>,
}
macro_rules! direct_interners_old {
($($name:ident: $method:ident($ty:ty),)+) => {
$(impl<'tcx> Borrow<$ty> for InternedInSet<'tcx, $ty> {
fn borrow<'a>(&'a self) -> &'a $ty {
@ -2121,8 +2165,8 @@ macro_rules! direct_interners {
}
}
direct_interners! {
region: mk_region(RegionKind),
// FIXME: eventually these should all be converted to `direct_interners`.
direct_interners_old! {
const_: mk_const(Const<'tcx>),
const_allocation: intern_const_alloc(Allocation),
layout: intern_layout(Layout),

View file

@ -960,10 +960,10 @@ impl<'tcx> TypeVisitor<'tcx> for ValidateBoundVars<'tcx> {
}
fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
match r {
ty::ReLateBound(index, br) if *index == self.binder_index => {
match *r {
ty::ReLateBound(index, br) if index == self.binder_index => {
if self.bound_vars.len() <= br.var.as_usize() {
bug!("Not enough bound vars: {:?} not found in {:?}", *br, self.bound_vars);
bug!("Not enough bound vars: {:?} not found in {:?}", br, self.bound_vars);
}
let list_var = self.bound_vars[br.var.as_usize()];
match list_var {
@ -1076,9 +1076,9 @@ pub fn shift_region<'tcx>(
region: ty::Region<'tcx>,
amount: u32,
) -> ty::Region<'tcx> {
match region {
match *region {
ty::ReLateBound(debruijn, br) if amount > 0 => {
tcx.mk_region(ty::ReLateBound(debruijn.shifted_in(amount), *br))
tcx.mk_region(ty::ReLateBound(debruijn.shifted_in(amount), br))
}
_ => region,
}

View file

@ -326,19 +326,11 @@ pub fn characteristic_def_id_of_type(ty: Ty<'_>) -> Option<DefId> {
characteristic_def_id_of_type_cached(ty, &mut SsoHashSet::new())
}
impl<'tcx, P: Printer<'tcx>> Print<'tcx, P> for ty::RegionKind {
type Output = P::Region;
type Error = P::Error;
fn print(&self, cx: P) -> Result<Self::Output, Self::Error> {
cx.print_region(self)
}
}
impl<'tcx, P: Printer<'tcx>> Print<'tcx, P> for ty::Region<'_> {
type Output = P::Region;
type Error = P::Error;
fn print(&self, cx: P) -> Result<Self::Output, Self::Error> {
cx.print_region(self)
cx.print_region(*self)
}
}

View file

@ -131,11 +131,13 @@ pub fn with_no_visible_paths<F: FnOnce() -> R, R>(f: F) -> R {
///
/// Regions not selected by the region highlight mode are presently
/// unaffected.
#[derive(Copy, Clone, Default)]
pub struct RegionHighlightMode {
#[derive(Copy, Clone)]
pub struct RegionHighlightMode<'tcx> {
tcx: TyCtxt<'tcx>,
/// If enabled, when we see the selected region, use "`'N`"
/// instead of the ordinary behavior.
highlight_regions: [Option<(ty::RegionKind, usize)>; 3],
highlight_regions: [Option<(ty::Region<'tcx>, usize)>; 3],
/// If enabled, when printing a "free region" that originated from
/// the given `ty::BoundRegionKind`, print it as "`'1`". Free regions that would ordinarily
@ -147,12 +149,20 @@ pub struct RegionHighlightMode {
highlight_bound_region: Option<(ty::BoundRegionKind, usize)>,
}
impl RegionHighlightMode {
impl<'tcx> RegionHighlightMode<'tcx> {
pub fn new(tcx: TyCtxt<'tcx>) -> Self {
Self {
tcx,
highlight_regions: Default::default(),
highlight_bound_region: Default::default(),
}
}
/// If `region` and `number` are both `Some`, invokes
/// `highlighting_region`.
pub fn maybe_highlighting_region(
&mut self,
region: Option<ty::Region<'_>>,
region: Option<ty::Region<'tcx>>,
number: Option<usize>,
) {
if let Some(k) = region {
@ -163,24 +173,24 @@ impl RegionHighlightMode {
}
/// Highlights the region inference variable `vid` as `'N`.
pub fn highlighting_region(&mut self, region: ty::Region<'_>, number: usize) {
pub fn highlighting_region(&mut self, region: ty::Region<'tcx>, number: usize) {
let num_slots = self.highlight_regions.len();
let first_avail_slot =
self.highlight_regions.iter_mut().find(|s| s.is_none()).unwrap_or_else(|| {
bug!("can only highlight {} placeholders at a time", num_slots,)
});
*first_avail_slot = Some((*region, number));
*first_avail_slot = Some((region, number));
}
/// Convenience wrapper for `highlighting_region`.
pub fn highlighting_region_vid(&mut self, vid: ty::RegionVid, number: usize) {
self.highlighting_region(&ty::ReVar(vid), number)
self.highlighting_region(self.tcx.mk_region(ty::ReVar(vid)), number)
}
/// Returns `Some(n)` with the number to use for the given region, if any.
fn region_highlighted(&self, region: ty::Region<'_>) -> Option<usize> {
self.highlight_regions.iter().find_map(|h| match h {
Some((r, n)) if r == region => Some(*n),
Some((r, n)) if *r == region => Some(*n),
_ => None,
})
}
@ -1054,7 +1064,7 @@ pub trait PrettyPrinter<'tcx>:
// Don't print `'_` if there's no unerased regions.
let print_regions = args.iter().any(|arg| match arg.unpack() {
GenericArgKind::Lifetime(r) => *r != ty::ReErased,
GenericArgKind::Lifetime(r) => !r.is_erased(),
_ => false,
});
let mut args = args.iter().cloned().filter(|arg| match arg.unpack() {
@ -1536,7 +1546,7 @@ pub struct FmtPrinterData<'a, 'tcx, F> {
binder_depth: usize,
printed_type_count: usize,
pub region_highlight_mode: RegionHighlightMode,
pub region_highlight_mode: RegionHighlightMode<'tcx>,
pub name_resolver: Option<Box<&'a dyn Fn(ty::TyVid) -> Option<String>>>,
}
@ -1566,7 +1576,7 @@ impl<'a, 'tcx, F> FmtPrinter<'a, 'tcx, F> {
region_index: 0,
binder_depth: 0,
printed_type_count: 0,
region_highlight_mode: RegionHighlightMode::default(),
region_highlight_mode: RegionHighlightMode::new(tcx),
name_resolver: None,
}))
}
@ -1802,7 +1812,7 @@ impl<'tcx, F: fmt::Write> Printer<'tcx> for FmtPrinter<'_, 'tcx, F> {
// Don't print `'_` if there's no unerased regions.
let print_regions = self.tcx.sess.verbose()
|| args.iter().any(|arg| match arg.unpack() {
GenericArgKind::Lifetime(r) => *r != ty::ReErased,
GenericArgKind::Lifetime(r) => !r.is_erased(),
_ => false,
});
let args = args.iter().cloned().filter(|arg| match arg.unpack() {
@ -2061,7 +2071,7 @@ impl<'a, 'tcx> ty::TypeFolder<'tcx> for RegionFolder<'a, 'tcx> {
fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
let name = &mut self.name;
let region = match *r {
ty::ReLateBound(_, br) => self.region_map.entry(br).or_insert_with(|| name(br)),
ty::ReLateBound(_, br) => *self.region_map.entry(br).or_insert_with(|| name(br)),
ty::RePlaceholder(ty::PlaceholderRegion { name: kind, .. }) => {
// If this is an anonymous placeholder, don't rename. Otherwise, in some
// async fns, we get a `for<'r> Send` bound
@ -2070,7 +2080,7 @@ impl<'a, 'tcx> ty::TypeFolder<'tcx> for RegionFolder<'a, 'tcx> {
_ => {
// Index doesn't matter, since this is just for naming and these never get bound
let br = ty::BoundRegion { var: ty::BoundVar::from_u32(0), kind };
self.region_map.entry(br).or_insert_with(|| name(br))
*self.region_map.entry(br).or_insert_with(|| name(br))
}
}
}
@ -2272,7 +2282,7 @@ impl<'tcx, F: fmt::Write> FmtPrinter<'_, 'tcx, F> {
#[instrument(skip(self), level = "trace")]
fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
trace!("address: {:p}", r);
trace!("address: {:p}", r.0.0);
if let ty::ReLateBound(_, ty::BoundRegion { kind: ty::BrNamed(_, name), .. }) = *r {
self.used_region_names.insert(name);
} else if let ty::RePlaceholder(ty::PlaceholderRegion {
@ -2369,7 +2379,7 @@ macro_rules! define_print_and_forward_display {
}
// HACK(eddyb) this is separate because `ty::RegionKind` doesn't need lifting.
impl fmt::Display for ty::RegionKind {
impl<'tcx> fmt::Display for ty::Region<'tcx> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
ty::tls::with(|tcx| {
self.print(FmtPrinter::new(tcx, f, Namespace::TypeNS))?;

View file

@ -12,6 +12,7 @@ use crate::ty::{self, AdtDef, DefIdTree, Discr, Term, Ty, TyCtxt, TypeFlags, Typ
use crate::ty::{DelaySpanBugEmitted, List, ParamEnv};
use polonius_engine::Atom;
use rustc_data_structures::captures::Captures;
use rustc_data_structures::intern::Interned;
use rustc_hir as hir;
use rustc_hir::def_id::DefId;
use rustc_index::vec::Idx;
@ -21,8 +22,9 @@ use rustc_target::abi::VariantIdx;
use rustc_target::spec::abi;
use std::borrow::Cow;
use std::cmp::Ordering;
use std::fmt;
use std::marker::PhantomData;
use std::ops::Range;
use std::ops::{Deref, Range};
use ty::util::IntTypeExt;
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, TyEncodable, TyDecodable)]
@ -1391,7 +1393,24 @@ impl ParamConst {
}
}
pub type Region<'tcx> = &'tcx RegionKind;
/// Use this rather than `TyKind`, whenever possible.
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, HashStable)]
#[cfg_attr(not(bootstrap), rustc_pass_by_value)]
pub struct Region<'tcx>(pub Interned<'tcx, RegionKind>);
impl<'tcx> Deref for Region<'tcx> {
type Target = RegionKind;
fn deref(&self) -> &RegionKind {
&self.0.0
}
}
impl<'tcx> fmt::Debug for Region<'tcx> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{:?}", self.kind())
}
}
/// Representation of regions. Note that the NLL checker uses a distinct
/// representation of regions. For this reason, it internally replaces all the
@ -1399,6 +1418,9 @@ pub type Region<'tcx> = &'tcx RegionKind;
/// to index into internal NLL data structures. See `rustc_const_eval::borrow_check`
/// module for more information.
///
/// Note: operations are on the wrapper `Region` type, which is interned,
/// rather than this type.
///
/// ## The Region lattice within a given function
///
/// In general, the region lattice looks like
@ -1655,9 +1677,13 @@ impl<'tcx> PolyExistentialProjection<'tcx> {
}
/// Region utilities
impl RegionKind {
impl<'tcx> Region<'tcx> {
pub fn kind(self) -> RegionKind {
*self.0.0
}
/// Is this region named by the user?
pub fn has_name(&self) -> bool {
pub fn has_name(self) -> bool {
match *self {
RegionKind::ReEarlyBound(ebr) => ebr.has_name(),
RegionKind::ReLateBound(_, br) => br.kind.is_named(),
@ -1671,24 +1697,39 @@ impl RegionKind {
}
#[inline]
pub fn is_late_bound(&self) -> bool {
pub fn is_static(self) -> bool {
matches!(*self, ty::ReStatic)
}
#[inline]
pub fn is_erased(self) -> bool {
matches!(*self, ty::ReErased)
}
#[inline]
pub fn is_late_bound(self) -> bool {
matches!(*self, ty::ReLateBound(..))
}
#[inline]
pub fn is_placeholder(&self) -> bool {
pub fn is_placeholder(self) -> bool {
matches!(*self, ty::RePlaceholder(..))
}
#[inline]
pub fn bound_at_or_above_binder(&self, index: ty::DebruijnIndex) -> bool {
pub fn is_empty(self) -> bool {
matches!(*self, ty::ReEmpty(..))
}
#[inline]
pub fn bound_at_or_above_binder(self, index: ty::DebruijnIndex) -> bool {
match *self {
ty::ReLateBound(debruijn, _) => debruijn >= index,
_ => false,
}
}
pub fn type_flags(&self) -> TypeFlags {
pub fn type_flags(self) -> TypeFlags {
let mut flags = TypeFlags::empty();
match *self {
@ -1746,8 +1787,8 @@ impl RegionKind {
/// of the impl, and for all the other highlighted regions, it
/// would return the `DefId` of the function. In other cases (not shown), this
/// function might return the `DefId` of a closure.
pub fn free_region_binding_scope(&self, tcx: TyCtxt<'_>) -> DefId {
match self {
pub fn free_region_binding_scope(self, tcx: TyCtxt<'_>) -> DefId {
match *self {
ty::ReEarlyBound(br) => tcx.parent(br.def_id).unwrap(),
ty::ReFree(fr) => fr.scope,
_ => bug!("free_region_binding_scope invoked on inappropriate region: {:?}", self),

View file

@ -26,6 +26,9 @@ use std::ops::ControlFlow;
/// To reduce memory usage, a `GenericArg` is an interned pointer,
/// with the lowest 2 bits being reserved for a tag to
/// indicate the type (`Ty`, `Region`, or `Const`) it points to.
///
/// Note: the `PartialEq`, `Eq` and `Hash` derives are only valid because `Ty`,
/// `Region` and `Const` are all interned.
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
pub struct GenericArg<'tcx> {
ptr: NonZeroUsize,
@ -49,8 +52,8 @@ impl<'tcx> GenericArgKind<'tcx> {
let (tag, ptr) = match self {
GenericArgKind::Lifetime(lt) => {
// Ensure we can use the tag bits.
assert_eq!(mem::align_of_val(lt) & TAG_MASK, 0);
(REGION_TAG, lt as *const ty::RegionKind as usize)
assert_eq!(mem::align_of_val(lt.0.0) & TAG_MASK, 0);
(REGION_TAG, lt.0.0 as *const ty::RegionKind as usize)
}
GenericArgKind::Type(ty) => {
// Ensure we can use the tag bits.
@ -117,9 +120,9 @@ impl<'tcx> GenericArg<'tcx> {
// and this is just going in the other direction.
unsafe {
match ptr & TAG_MASK {
REGION_TAG => {
GenericArgKind::Lifetime(&*((ptr & !TAG_MASK) as *const ty::RegionKind))
}
REGION_TAG => GenericArgKind::Lifetime(ty::Region(Interned::new_unchecked(
&*((ptr & !TAG_MASK) as *const ty::RegionKind),
))),
TYPE_TAG => GenericArgKind::Type(Ty(Interned::new_unchecked(
&*((ptr & !TAG_MASK) as *const ty::TyS<'tcx>),
))),

View file

@ -5,8 +5,9 @@ use crate::ty::fold::{FallibleTypeFolder, TypeFolder};
use crate::ty::layout::IntegerExt;
use crate::ty::query::TyCtxtAt;
use crate::ty::subst::{GenericArgKind, Subst, SubstsRef};
use crate::ty::TyKind::*;
use crate::ty::{self, DebruijnIndex, DefIdTree, List, Ty, TyCtxt, TypeFoldable};
use crate::ty::{
self, DebruijnIndex, DefIdTree, List, ReEarlyBound, Region, Ty, TyCtxt, TyKind::*, TypeFoldable,
};
use rustc_apfloat::Float as _;
use rustc_ast as ast;
use rustc_attr::{self as attr, SignedInt, UnsignedInt};
@ -390,7 +391,7 @@ impl<'tcx> TyCtxt<'tcx> {
let result = iter::zip(item_substs, impl_substs)
.filter(|&(_, k)| {
match k.unpack() {
GenericArgKind::Lifetime(&ty::RegionKind::ReEarlyBound(ref ebr)) => {
GenericArgKind::Lifetime(Region(Interned(ReEarlyBound(ref ebr), _))) => {
!impl_generics.region_param(ebr, self).pure_wrt_drop
}
GenericArgKind::Type(Ty(Interned(