From 3851e42792c6b5901fab10c035318b8cf0fe1a3c Mon Sep 17 00:00:00 2001 From: Markus Westerlind Date: Sun, 5 Jan 2020 12:47:11 +0100 Subject: [PATCH 1/8] feat: Add a `ty::View` `ty::View<'tcx, T>` acts like a `T` but internally stores a `Ty<'tcx>` pointer. Thanks to this, it is possible to retrieve the original `Ty` value without needing to ask the interner for it. Looking up the already created type (`T`) takes a good chunk of the time in `infer/outlives/verify.rs` so this should be a good speedup. It may be applicable in other places as well, but those are far lower when profiling. --- src/librustc/infer/outlives/obligations.rs | 2 +- src/librustc/infer/outlives/verify.rs | 10 +- src/librustc/infer/region_constraints/mod.rs | 2 +- src/librustc/traits/query/outlives_bounds.rs | 2 +- src/librustc/ty/mod.rs | 3 + src/librustc/ty/outlives.rs | 6 +- src/librustc/ty/structural_impls.rs | 18 ++ src/librustc/ty/view.rs | 182 +++++++++++++++++++ 8 files changed, 214 insertions(+), 11 deletions(-) create mode 100644 src/librustc/ty/view.rs diff --git a/src/librustc/infer/outlives/obligations.rs b/src/librustc/infer/outlives/obligations.rs index 45e4a84589eb5..a8cfb07a37a2d 100644 --- a/src/librustc/infer/outlives/obligations.rs +++ b/src/librustc/infer/outlives/obligations.rs @@ -321,7 +321,7 @@ where &mut self, origin: infer::SubregionOrigin<'tcx>, region: ty::Region<'tcx>, - param_ty: ty::ParamTy, + param_ty: ty::View<'tcx, ty::ParamTy>, ) { debug!( "param_ty_must_outlive(region={:?}, param_ty={:?}, origin={:?})", diff --git a/src/librustc/infer/outlives/verify.rs b/src/librustc/infer/outlives/verify.rs index 8ee8482e79dbc..b780089597693 100644 --- a/src/librustc/infer/outlives/verify.rs +++ b/src/librustc/infer/outlives/verify.rs @@ -2,7 +2,7 @@ use crate::infer::outlives::env::RegionBoundPairs; use crate::infer::{GenericKind, VerifyBound}; use crate::traits; use crate::ty::subst::{InternalSubsts, Subst}; -use crate::ty::{self, Ty, TyCtxt}; +use crate::ty::{self, Ty, TyCtxt, View}; use rustc_data_structures::captures::Captures; use rustc_hir::def_id::DefId; @@ -40,13 +40,13 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> { fn type_bound(&self, ty: Ty<'tcx>) -> VerifyBound<'tcx> { match ty.kind { - ty::Param(p) => self.param_bound(p), + ty::Param(_) => self.param_bound(View::new(ty).unwrap()), ty::Projection(data) => self.projection_bound(data), _ => self.recursive_type_bound(ty), } } - fn param_bound(&self, param_ty: ty::ParamTy) -> VerifyBound<'tcx> { + fn param_bound(&self, param_ty: View<'tcx, ty::ParamTy>) -> VerifyBound<'tcx> { debug!("param_bound(param_ty={:?})", param_ty); // Start with anything like `T: 'a` we can scrape from the @@ -161,9 +161,9 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> { /// bounds, but all the bounds it returns can be relied upon. fn declared_generic_bounds_from_env( &self, - generic: GenericKind<'tcx>, + generic: View<'tcx, ty::ParamTy>, ) -> Vec, ty::Region<'tcx>>> { - let generic_ty = generic.to_ty(self.tcx); + let generic_ty = generic.as_ty(); self.declared_generic_bounds_from_env_with_compare_fn(|ty| ty == generic_ty) } diff --git a/src/librustc/infer/region_constraints/mod.rs b/src/librustc/infer/region_constraints/mod.rs index f218bf1134f7f..407c19ffd5f1b 100644 --- a/src/librustc/infer/region_constraints/mod.rs +++ b/src/librustc/infer/region_constraints/mod.rs @@ -184,7 +184,7 @@ pub struct Verify<'tcx> { #[derive(Copy, Clone, PartialEq, Eq, Hash, TypeFoldable)] pub enum GenericKind<'tcx> { - Param(ty::ParamTy), + Param(ty::View<'tcx, ty::ParamTy>), Projection(ty::ProjectionTy<'tcx>), } diff --git a/src/librustc/traits/query/outlives_bounds.rs b/src/librustc/traits/query/outlives_bounds.rs index 07e57e847b13d..04432fa37d4d5 100644 --- a/src/librustc/traits/query/outlives_bounds.rs +++ b/src/librustc/traits/query/outlives_bounds.rs @@ -20,7 +20,7 @@ use std::mem; #[derive(Clone, Debug, TypeFoldable, Lift)] pub enum OutlivesBound<'tcx> { RegionSubRegion(ty::Region<'tcx>, ty::Region<'tcx>), - RegionSubParam(ty::Region<'tcx>, ty::ParamTy), + RegionSubParam(ty::Region<'tcx>, ty::View<'tcx, ty::ParamTy>), RegionSubProjection(ty::Region<'tcx>, ty::ProjectionTy<'tcx>), } diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 282136fa3546b..e37d31ebf815c 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -89,6 +89,8 @@ pub use self::trait_def::TraitDef; pub use self::query::queries; +pub use self::view::View; + pub mod adjustment; pub mod binding; pub mod cast; @@ -112,6 +114,7 @@ pub mod steal; pub mod subst; pub mod trait_def; pub mod util; +pub mod view; pub mod walk; mod context; diff --git a/src/librustc/ty/outlives.rs b/src/librustc/ty/outlives.rs index b397a2c80d59b..f0034e3ce4ea9 100644 --- a/src/librustc/ty/outlives.rs +++ b/src/librustc/ty/outlives.rs @@ -8,7 +8,7 @@ use smallvec::SmallVec; #[derive(Debug)] pub enum Component<'tcx> { Region(ty::Region<'tcx>), - Param(ty::ParamTy), + Param(ty::View<'tcx, ty::ParamTy>), UnresolvedInferenceVariable(ty::InferTy), // Projections like `T::Foo` are tricky because a constraint like @@ -82,8 +82,8 @@ fn compute_components(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, out: &mut SmallVec<[Compo // OutlivesTypeParameterEnv -- the actual checking that `X:'a` // is implied by the environment is done in regionck. - ty::Param(p) => { - out.push(Component::Param(p)); + ty::Param(_) => { + out.push(Component::Param(ty::View::new(ty).unwrap())); } // For projections, we prefer to generate an obligation like diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs index 62e895af7f355..d28048c616b4d 100644 --- a/src/librustc/ty/structural_impls.rs +++ b/src/librustc/ty/structural_impls.rs @@ -13,6 +13,7 @@ use rustc_index::vec::{Idx, IndexVec}; use smallvec::SmallVec; use std::fmt; +use std::marker::PhantomData; use std::rc::Rc; use std::sync::Arc; @@ -389,6 +390,13 @@ impl<'tcx, I: Idx, T: Lift<'tcx>> Lift<'tcx> for IndexVec { } } +impl<'tcx, T: Lift<'tcx>> Lift<'tcx> for PhantomData { + type Lifted = PhantomData; + fn lift_to_tcx(&self, _tcx: TyCtxt<'tcx>) -> Option { + Some(PhantomData) + } +} + impl<'a, 'tcx> Lift<'tcx> for ty::TraitRef<'a> { type Lifted = ty::TraitRef<'tcx>; fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option { @@ -1067,3 +1075,13 @@ impl<'tcx> TypeFoldable<'tcx> for InferConst<'tcx> { false } } + +impl<'tcx, T> TypeFoldable<'tcx> for PhantomData { + fn super_fold_with>(&self, _folder: &mut F) -> Self { + *self + } + + fn super_visit_with>(&self, _visitor: &mut V) -> bool { + false + } +} diff --git a/src/librustc/ty/view.rs b/src/librustc/ty/view.rs new file mode 100644 index 0000000000000..e3e9179a9c7c9 --- /dev/null +++ b/src/librustc/ty/view.rs @@ -0,0 +1,182 @@ +use std::{fmt, marker::PhantomData}; + +use syntax::ast; + +use crate::{ + hir::{self, def_id::DefId}, + ty::{ + self, AdtDef, Binder, BoundTy, ExistentialPredicate, InferTy, List, ParamTy, PolyFnSig, + ProjectionTy, Region, SubstsRef, Ty, TypeAndMut, + }, +}; + +pub use self::ViewKind::*; + +// TODO Forward eq/hash? +#[derive(Eq, PartialEq, Hash, TypeFoldable, Lift)] +pub struct View<'tcx, T> { + ty: Ty<'tcx>, + _marker: PhantomData, +} + +impl Copy for View<'_, T> {} +impl Clone for View<'_, T> { + fn clone(&self) -> Self { + View { ty: self.ty, _marker: PhantomData } + } +} + +impl<'tcx, T> fmt::Debug for View<'tcx, T> +where + T: fmt::Debug, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.ty.fmt(f) + } +} + +impl<'tcx, T> fmt::Display for View<'tcx, T> +where + T: fmt::Display + TyDeref<'tcx> + 'tcx, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + (**self).fmt(f) + } +} +impl<'tcx, T> std::ops::Deref for View<'tcx, T> +where + T: TyDeref<'tcx> + 'tcx, +{ + type Target = T; + fn deref(&self) -> &Self::Target { + match T::ty_deref(self.ty) { + Some(t) => t, + // SAFETY verified by `View::new` + None => unsafe { std::hint::unreachable_unchecked() }, + } + } +} + +impl<'tcx, T> View<'tcx, T> +where + T: TyDeref<'tcx> + 'tcx, +{ + pub fn new(ty: Ty<'tcx>) -> Option { + T::ty_deref(ty)?; + Some(View { ty, _marker: PhantomData }) + } +} + +impl<'tcx, T> View<'tcx, T> { + pub fn as_ty(&self) -> Ty<'tcx> { + self.ty + } +} + +/// SAFETY If `Some` is returned for `ty` then `Some` must always be returned for any subsequent +/// call with the same `Ty` value +pub unsafe trait TyDeref<'tcx>: Sized { + fn ty_deref(ty: Ty<'tcx>) -> Option<&'tcx Self>; +} + +unsafe impl<'tcx> TyDeref<'tcx> for ty::ParamTy { + fn ty_deref(ty: Ty<'tcx>) -> Option<&'tcx Self> { + match &ty.kind { + ty::Param(p) => Some(p), + _ => None, + } + } +} + +pub enum ViewKind<'tcx> { + Bool, + + Char, + + Int(ast::IntTy), + + Uint(ast::UintTy), + + Float(ast::FloatTy), + + Adt(&'tcx AdtDef, SubstsRef<'tcx>), + + Foreign(DefId), + + Str, + + Array(Ty<'tcx>, &'tcx ty::Const<'tcx>), + + Slice(Ty<'tcx>), + + RawPtr(TypeAndMut<'tcx>), + + Ref(Region<'tcx>, Ty<'tcx>, hir::Mutability), + + FnDef(DefId, SubstsRef<'tcx>), + + FnPtr(PolyFnSig<'tcx>), + + Dynamic(Binder<&'tcx List>>, ty::Region<'tcx>), + + Closure(DefId, SubstsRef<'tcx>), + + Generator(DefId, SubstsRef<'tcx>, hir::Movability), + + GeneratorWitness(Binder<&'tcx List>>), + + Never, + + Tuple(SubstsRef<'tcx>), + + Projection(ProjectionTy<'tcx>), + + UnnormalizedProjection(ProjectionTy<'tcx>), + + Opaque(DefId, SubstsRef<'tcx>), + + Param(View<'tcx, ParamTy>), + + Bound(ty::DebruijnIndex, BoundTy), + + Placeholder(ty::PlaceholderType), + + Infer(InferTy), + + Error, +} + +impl<'tcx> From> for ViewKind<'tcx> { + fn from(ty: Ty<'tcx>) -> Self { + match ty.kind { + ty::RawPtr(tm) => Self::RawPtr(tm), + ty::Array(typ, sz) => Self::Array(typ, sz), + ty::Slice(typ) => Self::Slice(typ), + ty::Adt(tid, substs) => Self::Adt(tid, substs), + ty::Dynamic(trait_ty, region) => Self::Dynamic(trait_ty, region), + ty::Tuple(ts) => Self::Tuple(ts), + ty::FnDef(def_id, substs) => Self::FnDef(def_id, substs), + ty::FnPtr(f) => Self::FnPtr(f), + ty::Ref(r, ty, mutbl) => Self::Ref(r, ty, mutbl), + ty::Generator(did, substs, movability) => Self::Generator(did, substs, movability), + ty::GeneratorWitness(types) => Self::GeneratorWitness(types), + ty::Closure(did, substs) => Self::Closure(did, substs), + ty::Projection(data) => Self::Projection(data), + ty::UnnormalizedProjection(data) => Self::UnnormalizedProjection(data), + ty::Opaque(did, substs) => Self::Opaque(did, substs), + ty::Bool => Self::Bool, + ty::Char => Self::Char, + ty::Str => Self::Str, + ty::Int(i) => Self::Int(i), + ty::Uint(i) => Self::Uint(i), + ty::Float(f) => Self::Float(f), + ty::Error => Self::Error, + ty::Infer(i) => Self::Infer(i), + ty::Param(_) => Self::Param(View::new(ty).unwrap()), + ty::Bound(b, c) => Self::Bound(b, c), + ty::Placeholder(p) => Self::Placeholder(p), + ty::Never => Self::Never, + ty::Foreign(f) => Self::Foreign(f), + } + } +} From 1b633b4f33abbcfd76b23dcd8a5638b58052188e Mon Sep 17 00:00:00 2001 From: Markus Westerlind Date: Sun, 5 Jan 2020 13:21:05 +0100 Subject: [PATCH 2/8] feat: Add `ViewKind` as a mirror on `TyKind` But it instead provies "view" types when possible --- .../infer/lexical_region_resolve/mod.rs | 2 +- src/librustc/infer/outlives/obligations.rs | 6 +- src/librustc/infer/outlives/verify.rs | 55 ++++++++-------- src/librustc/infer/region_constraints/mod.rs | 23 ++++--- src/librustc/traits/query/outlives_bounds.rs | 2 +- src/librustc/ty/outlives.rs | 62 +++++++++---------- src/librustc/ty/view.rs | 61 ++++++------------ src/librustc_data_structures/captures.rs | 7 ++- .../borrow_check/region_infer/mod.rs | 4 +- 9 files changed, 108 insertions(+), 114 deletions(-) diff --git a/src/librustc/infer/lexical_region_resolve/mod.rs b/src/librustc/infer/lexical_region_resolve/mod.rs index 0bc49a2901505..40909495c01da 100644 --- a/src/librustc/infer/lexical_region_resolve/mod.rs +++ b/src/librustc/infer/lexical_region_resolve/mod.rs @@ -602,7 +602,7 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { continue; } - let verify_kind_ty = verify.kind.to_ty(self.tcx()); + let verify_kind_ty = verify.kind.as_ty(); if self.bound_is_met(&verify.bound, var_data, verify_kind_ty, sub) { continue; } diff --git a/src/librustc/infer/outlives/obligations.rs b/src/librustc/infer/outlives/obligations.rs index a8cfb07a37a2d..da5afaad0e7bb 100644 --- a/src/librustc/infer/outlives/obligations.rs +++ b/src/librustc/infer/outlives/obligations.rs @@ -337,7 +337,7 @@ where &mut self, origin: infer::SubregionOrigin<'tcx>, region: ty::Region<'tcx>, - projection_ty: ty::ProjectionTy<'tcx>, + projection_ty: ty::View<'tcx, ty::ProjectionTy<'tcx>>, ) { debug!( "projection_must_outlive(region={:?}, projection_ty={:?}, origin={:?})", @@ -376,8 +376,8 @@ where // #55756) in cases where you have e.g., `>::Item: // 'a` in the environment but `trait Foo<'b> { type Item: 'b // }` in the trait definition. - approx_env_bounds.retain(|bound| match bound.0.kind { - ty::Projection(projection_ty) => self + approx_env_bounds.retain(|bound| match bound.0.into() { + ty::view::Projection(projection_ty) => self .verify_bound .projection_declared_bounds_from_trait(projection_ty) .all(|r| r != bound.1), diff --git a/src/librustc/infer/outlives/verify.rs b/src/librustc/infer/outlives/verify.rs index b780089597693..752c2cc410f81 100644 --- a/src/librustc/infer/outlives/verify.rs +++ b/src/librustc/infer/outlives/verify.rs @@ -39,9 +39,9 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> { } fn type_bound(&self, ty: Ty<'tcx>) -> VerifyBound<'tcx> { - match ty.kind { - ty::Param(_) => self.param_bound(View::new(ty).unwrap()), - ty::Projection(data) => self.projection_bound(data), + match ty.into() { + ty::view::Param(p) => self.param_bound(p), + ty::view::Projection(data) => self.projection_bound(data), _ => self.recursive_type_bound(ty), } } @@ -78,9 +78,9 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> { /// this list. pub fn projection_approx_declared_bounds_from_env( &self, - projection_ty: ty::ProjectionTy<'tcx>, + projection_ty: ty::View<'tcx, ty::ProjectionTy<'tcx>>, ) -> Vec, ty::Region<'tcx>>> { - let projection_ty = GenericKind::Projection(projection_ty).to_ty(self.tcx); + let projection_ty = projection_ty.as_ty(); let erased_projection_ty = self.tcx.erase_regions(&projection_ty); self.declared_generic_bounds_from_env_with_compare_fn(|ty| { if let ty::Projection(..) = ty.kind { @@ -97,32 +97,37 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> { /// exact match. pub fn projection_declared_bounds_from_trait( &self, - projection_ty: ty::ProjectionTy<'tcx>, + projection_ty: ty::View<'tcx, ty::ProjectionTy<'tcx>>, ) -> impl Iterator> + 'cx + Captures<'tcx> { self.declared_projection_bounds_from_trait(projection_ty) } - pub fn projection_bound(&self, projection_ty: ty::ProjectionTy<'tcx>) -> VerifyBound<'tcx> { + pub fn projection_bound( + &self, + projection_ty: ty::View<'tcx, ty::ProjectionTy<'tcx>>, + ) -> VerifyBound<'tcx> { debug!("projection_bound(projection_ty={:?})", projection_ty); - let projection_ty_as_ty = - self.tcx.mk_projection(projection_ty.item_def_id, projection_ty.substs); + let projection_ty_as_ty = projection_ty.as_ty(); + + let mut bounds = Vec::new(); // Search the env for where clauses like `P: 'a`. - let env_bounds = self - .projection_approx_declared_bounds_from_env(projection_ty) - .into_iter() - .map(|ty::OutlivesPredicate(ty, r)| { - let vb = VerifyBound::OutlivedBy(r); - if ty == projection_ty_as_ty { - // Micro-optimize if this is an exact match (this - // occurs often when there are no region variables - // involved). - vb - } else { - VerifyBound::IfEq(ty, Box::new(vb)) - } - }); + bounds.extend( + self.projection_approx_declared_bounds_from_env(projection_ty).into_iter().map( + |ty::OutlivesPredicate(ty, r)| { + let vb = VerifyBound::OutlivedBy(r); + if ty == projection_ty_as_ty { + // Micro-optimize if this is an exact match (this + // occurs often when there are no region variables + // involved). + vb + } else { + VerifyBound::IfEq(ty, Box::new(vb)) + } + }, + ), + ); // Extend with bounds that we can find from the trait. let trait_bounds = self @@ -198,7 +203,7 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> { "declared_generic_bounds_from_env_with_compare_fn: region_bound_pair = {:?}", (r, p) ); - let p_ty = p.to_ty(tcx); + let p_ty = p.as_ty(); compare_ty(p_ty).then_some(ty::OutlivesPredicate(p_ty, r)) }); @@ -227,7 +232,7 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> { /// `region_bounds_declared_on_associated_item`. fn declared_projection_bounds_from_trait( &self, - projection_ty: ty::ProjectionTy<'tcx>, + projection_ty: ty::View<'tcx, ty::ProjectionTy<'tcx>>, ) -> impl Iterator> + 'cx + Captures<'tcx> { debug!("projection_bounds(projection_ty={:?})", projection_ty); let tcx = self.tcx; diff --git a/src/librustc/infer/region_constraints/mod.rs b/src/librustc/infer/region_constraints/mod.rs index 407c19ffd5f1b..32bc3844d0d2a 100644 --- a/src/librustc/infer/region_constraints/mod.rs +++ b/src/librustc/infer/region_constraints/mod.rs @@ -185,7 +185,7 @@ pub struct Verify<'tcx> { #[derive(Copy, Clone, PartialEq, Eq, Hash, TypeFoldable)] pub enum GenericKind<'tcx> { Param(ty::View<'tcx, ty::ParamTy>), - Projection(ty::ProjectionTy<'tcx>), + Projection(ty::View<'tcx, ty::ProjectionTy<'tcx>>), } /// Describes the things that some `GenericKind` value `G` is known to @@ -875,10 +875,10 @@ impl<'tcx> fmt::Display for GenericKind<'tcx> { } impl<'tcx> GenericKind<'tcx> { - pub fn to_ty(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> { + pub fn as_ty(&self) -> Ty<'tcx> { match *self { - GenericKind::Param(ref p) => p.to_ty(tcx), - GenericKind::Projection(ref p) => tcx.mk_projection(p.item_def_id, p.substs), + GenericKind::Param(ref p) => p.as_ty(), + GenericKind::Projection(ref p) => p.as_ty(), } } } @@ -904,13 +904,18 @@ impl<'tcx> VerifyBound<'tcx> { } } - pub fn or(self, vb: VerifyBound<'tcx>) -> VerifyBound<'tcx> { - if self.must_hold() || vb.cannot_hold() { + pub fn or(self, vb: impl FnOnce() -> VerifyBound<'tcx>) -> VerifyBound<'tcx> { + if self.must_hold() { self - } else if self.cannot_hold() || vb.must_hold() { - vb } else { - VerifyBound::AnyBound(vec![self, vb]) + let vb = vb(); + if vb.cannot_hold() { + self + } else if self.cannot_hold() || vb.must_hold() { + vb + } else { + VerifyBound::AnyBound(vec![self, vb]) + } } } diff --git a/src/librustc/traits/query/outlives_bounds.rs b/src/librustc/traits/query/outlives_bounds.rs index 04432fa37d4d5..b3f21491fdeb5 100644 --- a/src/librustc/traits/query/outlives_bounds.rs +++ b/src/librustc/traits/query/outlives_bounds.rs @@ -21,7 +21,7 @@ use std::mem; pub enum OutlivesBound<'tcx> { RegionSubRegion(ty::Region<'tcx>, ty::Region<'tcx>), RegionSubParam(ty::Region<'tcx>, ty::View<'tcx, ty::ParamTy>), - RegionSubProjection(ty::Region<'tcx>, ty::ProjectionTy<'tcx>), + RegionSubProjection(ty::Region<'tcx>, ty::View<'tcx, ty::ProjectionTy<'tcx>>), } impl<'a, 'tcx> HashStable> for OutlivesBound<'tcx> { diff --git a/src/librustc/ty/outlives.rs b/src/librustc/ty/outlives.rs index f0034e3ce4ea9..862f49d18c65a 100644 --- a/src/librustc/ty/outlives.rs +++ b/src/librustc/ty/outlives.rs @@ -20,7 +20,7 @@ pub enum Component<'tcx> { // is not in a position to judge which is the best technique, so // we just product the projection as a component and leave it to // the consumer to decide (but see `EscapingProjection` below). - Projection(ty::ProjectionTy<'tcx>), + Projection(ty::View<'tcx, ty::ProjectionTy<'tcx>>), // In the case where a projection has escaping regions -- meaning // regions bound within the type itself -- we always use @@ -61,13 +61,13 @@ fn compute_components(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, out: &mut SmallVec<[Compo // in the `subtys` iterator (e.g., when encountering a // projection). match ty.kind { - ty::Closure(def_id, ref substs) => { + ty::view::Closure(def_id, ref substs) => { for upvar_ty in substs.as_closure().upvar_tys(def_id, tcx) { compute_components(tcx, upvar_ty, out); } } - ty::Generator(def_id, ref substs, _) => { + ty::view::Generator(def_id, ref substs, _) => { // Same as the closure case for upvar_ty in substs.as_generator().upvar_tys(def_id, tcx) { compute_components(tcx, upvar_ty, out); @@ -78,12 +78,12 @@ fn compute_components(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, out: &mut SmallVec<[Compo } // All regions are bound inside a witness - ty::GeneratorWitness(..) => (), + ty::view::GeneratorWitness(..) => (), // OutlivesTypeParameterEnv -- the actual checking that `X:'a` // is implied by the environment is done in regionck. - ty::Param(_) => { - out.push(Component::Param(ty::View::new(ty).unwrap())); + ty::view::Param(p) => { + out.push(Component::Param(p)); } // For projections, we prefer to generate an obligation like @@ -94,7 +94,7 @@ fn compute_components(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, out: &mut SmallVec<[Compo // trait-ref. Therefore, if we see any higher-ranke regions, // we simply fallback to the most restrictive rule, which // requires that `Pi: 'a` for all `i`. - ty::Projection(ref data) => { + ty::view::Projection(data) => { if !data.has_escaping_bound_vars() { // best case: no escaping regions, so push the // projection and skip the subtree (thus generating no @@ -102,7 +102,7 @@ fn compute_components(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, out: &mut SmallVec<[Compo // the rules OutlivesProjectionEnv, // OutlivesProjectionTraitDef, and // OutlivesProjectionComponents to regionck. - out.push(Component::Projection(*data)); + out.push(Component::Projection(data)); } else { // fallback case: hard code // OutlivesProjectionComponents. Continue walking @@ -112,12 +112,12 @@ fn compute_components(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, out: &mut SmallVec<[Compo } } - ty::UnnormalizedProjection(..) => bug!("only used with chalk-engine"), + ty::view::UnnormalizedProjection(..) => bug!("only used with chalk-engine"), // We assume that inference variables are fully resolved. // So, if we encounter an inference variable, just record // the unresolved variable as a component. - ty::Infer(infer_ty) => { + ty::view::Infer(infer_ty) => { out.push(Component::UnresolvedInferenceVariable(infer_ty)); } @@ -127,27 +127,27 @@ fn compute_components(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, out: &mut SmallVec<[Compo // the type and then visits the types that are lexically // contained within. (The comments refer to relevant rules // from RFC1214.) - ty::Bool | // OutlivesScalar - ty::Char | // OutlivesScalar - ty::Int(..) | // OutlivesScalar - ty::Uint(..) | // OutlivesScalar - ty::Float(..) | // OutlivesScalar - ty::Never | // ... - ty::Adt(..) | // OutlivesNominalType - ty::Opaque(..) | // OutlivesNominalType (ish) - ty::Foreign(..) | // OutlivesNominalType - ty::Str | // OutlivesScalar (ish) - ty::Array(..) | // ... - ty::Slice(..) | // ... - ty::RawPtr(..) | // ... - ty::Ref(..) | // OutlivesReference - ty::Tuple(..) | // ... - ty::FnDef(..) | // OutlivesFunction (*) - ty::FnPtr(_) | // OutlivesFunction (*) - ty::Dynamic(..) | // OutlivesObject, OutlivesFragment (*) - ty::Placeholder(..) | - ty::Bound(..) | - ty::Error => { + ty::view::Bool | // OutlivesScalar + ty::view::Char | // OutlivesScalar + ty::view::Int(..) | // OutlivesScalar + ty::view::Uint(..) | // OutlivesScalar + ty::view::Float(..) | // OutlivesScalar + ty::view::Never | // ... + ty::view::Adt(..) | // OutlivesNominalType + ty::view::Opaque(..) | // OutlivesNominalType (ish) + ty::view::Foreign(..) | // OutlivesNominalType + ty::view::Str | // OutlivesScalar (ish) + ty::view::Array(..) | // ... + ty::view::Slice(..) | // ... + ty::view::RawPtr(..) | // ... + ty::view::Ref(..) | // OutlivesReference + ty::view::Tuple(..) | // ... + ty::view::FnDef(..) | // OutlivesFunction (*) + ty::view::FnPtr(_) | // OutlivesFunction (*) + ty::view::Dynamic(..) | // OutlivesObject, OutlivesFragment (*) + ty::view::Placeholder(..) | + ty::view::Bound(..) | + ty::view::Error => { // (*) Bare functions and traits are both binders. In the // RFC, this means we would add the bound regions to the // "bound regions list". In our representation, no such diff --git a/src/librustc/ty/view.rs b/src/librustc/ty/view.rs index e3e9179a9c7c9..0b50c7870dc56 100644 --- a/src/librustc/ty/view.rs +++ b/src/librustc/ty/view.rs @@ -2,13 +2,11 @@ use std::{fmt, marker::PhantomData}; use syntax::ast; -use crate::{ - hir::{self, def_id::DefId}, - ty::{ - self, AdtDef, Binder, BoundTy, ExistentialPredicate, InferTy, List, ParamTy, PolyFnSig, - ProjectionTy, Region, SubstsRef, Ty, TypeAndMut, - }, +use crate::ty::{ + self, AdtDef, Binder, BoundTy, ExistentialPredicate, InferTy, List, ParamTy, PolyFnSig, + ProjectionTy, Region, SubstsRef, Ty, TypeAndMut, }; +use rustc_hir::{self as hir, def_id::DefId}; pub use self::ViewKind::*; @@ -79,70 +77,51 @@ pub unsafe trait TyDeref<'tcx>: Sized { fn ty_deref(ty: Ty<'tcx>) -> Option<&'tcx Self>; } -unsafe impl<'tcx> TyDeref<'tcx> for ty::ParamTy { - fn ty_deref(ty: Ty<'tcx>) -> Option<&'tcx Self> { - match &ty.kind { - ty::Param(p) => Some(p), - _ => None, +macro_rules! impl_ty_deref { + ($ty: ty, $variant: ident) => { + unsafe impl<'tcx> TyDeref<'tcx> for $ty { + fn ty_deref(ty: Ty<'tcx>) -> Option<&'tcx Self> { + match &ty.kind { + ty::$variant(p) => Some(p), + _ => None, + } + } } - } + }; } +impl_ty_deref! { ty::ParamTy, Param } +impl_ty_deref! { ty::ProjectionTy<'tcx>, Projection } + +/// Mirror of `TyKind`, but with `View` fields where there is need for it pub enum ViewKind<'tcx> { Bool, - Char, - Int(ast::IntTy), - Uint(ast::UintTy), - Float(ast::FloatTy), - Adt(&'tcx AdtDef, SubstsRef<'tcx>), - Foreign(DefId), - Str, - Array(Ty<'tcx>, &'tcx ty::Const<'tcx>), - Slice(Ty<'tcx>), - RawPtr(TypeAndMut<'tcx>), - Ref(Region<'tcx>, Ty<'tcx>, hir::Mutability), - FnDef(DefId, SubstsRef<'tcx>), - FnPtr(PolyFnSig<'tcx>), - Dynamic(Binder<&'tcx List>>, ty::Region<'tcx>), - Closure(DefId, SubstsRef<'tcx>), - Generator(DefId, SubstsRef<'tcx>, hir::Movability), - GeneratorWitness(Binder<&'tcx List>>), - Never, - Tuple(SubstsRef<'tcx>), - - Projection(ProjectionTy<'tcx>), - + Projection(View<'tcx, ProjectionTy<'tcx>>), UnnormalizedProjection(ProjectionTy<'tcx>), - Opaque(DefId, SubstsRef<'tcx>), - Param(View<'tcx, ParamTy>), - Bound(ty::DebruijnIndex, BoundTy), - Placeholder(ty::PlaceholderType), - Infer(InferTy), - Error, } @@ -161,7 +140,7 @@ impl<'tcx> From> for ViewKind<'tcx> { ty::Generator(did, substs, movability) => Self::Generator(did, substs, movability), ty::GeneratorWitness(types) => Self::GeneratorWitness(types), ty::Closure(did, substs) => Self::Closure(did, substs), - ty::Projection(data) => Self::Projection(data), + ty::Projection(_) => Self::Projection(View::new(ty).unwrap()), ty::UnnormalizedProjection(data) => Self::UnnormalizedProjection(data), ty::Opaque(did, substs) => Self::Opaque(did, substs), ty::Bool => Self::Bool, diff --git a/src/librustc_data_structures/captures.rs b/src/librustc_data_structures/captures.rs index 26b90ebfd5f11..ea2452187ee97 100644 --- a/src/librustc_data_structures/captures.rs +++ b/src/librustc_data_structures/captures.rs @@ -7,4 +7,9 @@ #[allow(unused_lifetimes)] pub trait Captures<'a> {} -impl<'a, T: ?Sized> Captures<'a> for T {} +impl Captures<'_> for T {} + +#[allow(unused_lifetimes)] +pub trait Captures2<'a, 'b> {} + +impl Captures2<'_, '_> for T {} diff --git a/src/librustc_mir/borrow_check/region_infer/mod.rs b/src/librustc_mir/borrow_check/region_infer/mod.rs index 7d2384f8a7de7..1d3307fe39d11 100644 --- a/src/librustc_mir/borrow_check/region_infer/mod.rs +++ b/src/librustc_mir/borrow_check/region_infer/mod.rs @@ -815,7 +815,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { for type_test in &self.type_tests { debug!("check_type_test: {:?}", type_test); - let generic_ty = type_test.generic_kind.to_ty(tcx); + let generic_ty = type_test.generic_kind.as_ty(); if self.eval_verify_bound( tcx, body, @@ -910,7 +910,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { let TypeTest { generic_kind, lower_bound, locations, verify_bound: _ } = type_test; - let generic_ty = generic_kind.to_ty(tcx); + let generic_ty = generic_kind.as_ty(); let subject = match self.try_promote_type_test_subject(infcx, generic_ty) { Some(s) => s, None => return false, From 284510eb21c69c814234f5456214efe4747aa855 Mon Sep 17 00:00:00 2001 From: Markus Westerlind Date: Sun, 5 Jan 2020 16:11:35 +0100 Subject: [PATCH 3/8] Make View's Eq and Hash more correct --- src/librustc/ty/view.rs | 41 ++++++++++++++++++++++++++++++++++------- 1 file changed, 34 insertions(+), 7 deletions(-) diff --git a/src/librustc/ty/view.rs b/src/librustc/ty/view.rs index 0b50c7870dc56..f7f529e2ee107 100644 --- a/src/librustc/ty/view.rs +++ b/src/librustc/ty/view.rs @@ -1,4 +1,8 @@ -use std::{fmt, marker::PhantomData}; +use std::{ + fmt, + hash::{Hash, Hasher}, + marker::PhantomData, +}; use syntax::ast; @@ -10,14 +14,37 @@ use rustc_hir::{self as hir, def_id::DefId}; pub use self::ViewKind::*; -// TODO Forward eq/hash? -#[derive(Eq, PartialEq, Hash, TypeFoldable, Lift)] +#[derive(TypeFoldable, Lift)] pub struct View<'tcx, T> { ty: Ty<'tcx>, _marker: PhantomData, } +impl<'tcx, T> PartialEq for View<'tcx, T> +where + T: PartialEq + TyDeref<'tcx>, +{ + fn eq(&self, other: &Self) -> bool { + **self == **other + } +} + +impl<'tcx, T> Eq for View<'tcx, T> where T: Eq + TyDeref<'tcx> {} + +impl<'tcx, T> Hash for View<'tcx, T> +where + T: Hash + TyDeref<'tcx>, +{ + fn hash(&self, hasher: &mut H) + where + H: Hasher, + { + (**self).hash(hasher) + } +} + impl Copy for View<'_, T> {} + impl Clone for View<'_, T> { fn clone(&self) -> Self { View { ty: self.ty, _marker: PhantomData } @@ -35,7 +62,7 @@ where impl<'tcx, T> fmt::Display for View<'tcx, T> where - T: fmt::Display + TyDeref<'tcx> + 'tcx, + T: fmt::Display + TyDeref<'tcx>, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { (**self).fmt(f) @@ -43,7 +70,7 @@ where } impl<'tcx, T> std::ops::Deref for View<'tcx, T> where - T: TyDeref<'tcx> + 'tcx, + T: TyDeref<'tcx>, { type Target = T; fn deref(&self) -> &Self::Target { @@ -57,7 +84,7 @@ where impl<'tcx, T> View<'tcx, T> where - T: TyDeref<'tcx> + 'tcx, + T: TyDeref<'tcx>, { pub fn new(ty: Ty<'tcx>) -> Option { T::ty_deref(ty)?; @@ -73,7 +100,7 @@ impl<'tcx, T> View<'tcx, T> { /// SAFETY If `Some` is returned for `ty` then `Some` must always be returned for any subsequent /// call with the same `Ty` value -pub unsafe trait TyDeref<'tcx>: Sized { +pub unsafe trait TyDeref<'tcx>: Sized + 'tcx { fn ty_deref(ty: Ty<'tcx>) -> Option<&'tcx Self>; } From 390e4fe699b871ac4b9a52b2ad7d0e04bc3f4ed4 Mon Sep 17 00:00:00 2001 From: Markus Westerlind Date: Sun, 5 Jan 2020 16:15:50 +0100 Subject: [PATCH 4/8] Add doc to ty::View --- src/librustc/ty/view.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/librustc/ty/view.rs b/src/librustc/ty/view.rs index f7f529e2ee107..4cc96e842454f 100644 --- a/src/librustc/ty/view.rs +++ b/src/librustc/ty/view.rs @@ -14,6 +14,9 @@ use rustc_hir::{self as hir, def_id::DefId}; pub use self::ViewKind::*; +/// `View<'tcx, T>` contains a value of `T` but stores the `Ty<'tcx>` ptr that contains the `T` +/// This allows for cheap access to the `Ty<'tcx>` without needing to ask the type interner or +/// losing the `T` type. #[derive(TypeFoldable, Lift)] pub struct View<'tcx, T> { ty: Ty<'tcx>, From 0e2da11159141e871e81bb612a7b3c327db833b7 Mon Sep 17 00:00:00 2001 From: Markus Westerlind Date: Thu, 9 Jan 2020 19:28:43 +0100 Subject: [PATCH 5/8] Revert the non-view changes --- src/librustc/infer/outlives/verify.rs | 39 ++-- src/librustc/infer/region_constraints/mod.rs | 15 +- src/librustc/ty/outlives.rs | 176 +++++++++---------- src/librustc_data_structures/captures.rs | 5 - 4 files changed, 109 insertions(+), 126 deletions(-) diff --git a/src/librustc/infer/outlives/verify.rs b/src/librustc/infer/outlives/verify.rs index 752c2cc410f81..daa48b96ae856 100644 --- a/src/librustc/infer/outlives/verify.rs +++ b/src/librustc/infer/outlives/verify.rs @@ -51,10 +51,8 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> { // Start with anything like `T: 'a` we can scrape from the // environment - let param_bounds = self - .declared_generic_bounds_from_env(GenericKind::Param(param_ty)) - .into_iter() - .map(|outlives| outlives.1); + let param_bounds = + self.declared_generic_bounds_from_env(param_ty).into_iter().map(|outlives| outlives.1); // Add in the default bound of fn body that applies to all in // scope type parameters: @@ -110,24 +108,21 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> { let projection_ty_as_ty = projection_ty.as_ty(); - let mut bounds = Vec::new(); - // Search the env for where clauses like `P: 'a`. - bounds.extend( - self.projection_approx_declared_bounds_from_env(projection_ty).into_iter().map( - |ty::OutlivesPredicate(ty, r)| { - let vb = VerifyBound::OutlivedBy(r); - if ty == projection_ty_as_ty { - // Micro-optimize if this is an exact match (this - // occurs often when there are no region variables - // involved). - vb - } else { - VerifyBound::IfEq(ty, Box::new(vb)) - } - }, - ), - ); + let env_bounds = self + .projection_approx_declared_bounds_from_env(projection_ty) + .into_iter() + .map(|ty::OutlivesPredicate(ty, r)| { + let vb = VerifyBound::OutlivedBy(r); + if ty == projection_ty_as_ty { + // Micro-optimize if this is an exact match (this + // occurs often when there are no region variables + // involved). + vb + } else { + VerifyBound::IfEq(ty, Box::new(vb)) + } + }); // Extend with bounds that we can find from the trait. let trait_bounds = self @@ -176,8 +171,6 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> { &self, compare_ty: impl Fn(Ty<'tcx>) -> bool, ) -> Vec, ty::Region<'tcx>>> { - let tcx = self.tcx; - // To start, collect bounds from user environment. Note that // parameter environments are already elaborated, so we don't // have to worry about that. Comparing using `==` is a bit diff --git a/src/librustc/infer/region_constraints/mod.rs b/src/librustc/infer/region_constraints/mod.rs index 32bc3844d0d2a..8fc24bbcd95ef 100644 --- a/src/librustc/infer/region_constraints/mod.rs +++ b/src/librustc/infer/region_constraints/mod.rs @@ -904,18 +904,13 @@ impl<'tcx> VerifyBound<'tcx> { } } - pub fn or(self, vb: impl FnOnce() -> VerifyBound<'tcx>) -> VerifyBound<'tcx> { - if self.must_hold() { + pub fn or(self, vb: VerifyBound<'tcx>) -> VerifyBound<'tcx> { + if self.must_hold() || vb.cannot_hold() { self + } else if self.cannot_hold() || vb.must_hold() { + vb } else { - let vb = vb(); - if vb.cannot_hold() { - self - } else if self.cannot_hold() || vb.must_hold() { - vb - } else { - VerifyBound::AnyBound(vec![self, vb]) - } + VerifyBound::AnyBound(vec![self, vb]) } } diff --git a/src/librustc/ty/outlives.rs b/src/librustc/ty/outlives.rs index 862f49d18c65a..51679ff1b19d1 100644 --- a/src/librustc/ty/outlives.rs +++ b/src/librustc/ty/outlives.rs @@ -60,106 +60,106 @@ fn compute_components(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, out: &mut SmallVec<[Compo // with `collect()` because of the need to sometimes skip subtrees // in the `subtys` iterator (e.g., when encountering a // projection). - match ty.kind { - ty::view::Closure(def_id, ref substs) => { - for upvar_ty in substs.as_closure().upvar_tys(def_id, tcx) { - compute_components(tcx, upvar_ty, out); - } + match ty.into() { + ty::view::Closure(def_id, ref substs) => { + for upvar_ty in substs.as_closure().upvar_tys(def_id, tcx) { + compute_components(tcx, upvar_ty, out); } + } - ty::view::Generator(def_id, ref substs, _) => { - // Same as the closure case - for upvar_ty in substs.as_generator().upvar_tys(def_id, tcx) { - compute_components(tcx, upvar_ty, out); - } - - // We ignore regions in the generator interior as we don't - // want these to affect region inference + ty::view::Generator(def_id, ref substs, _) => { + // Same as the closure case + for upvar_ty in substs.as_generator().upvar_tys(def_id, tcx) { + compute_components(tcx, upvar_ty, out); } - // All regions are bound inside a witness - ty::view::GeneratorWitness(..) => (), + // We ignore regions in the generator interior as we don't + // want these to affect region inference + } - // OutlivesTypeParameterEnv -- the actual checking that `X:'a` - // is implied by the environment is done in regionck. - ty::view::Param(p) => { - out.push(Component::Param(p)); - } + // All regions are bound inside a witness + ty::view::GeneratorWitness(..) => (), + + // OutlivesTypeParameterEnv -- the actual checking that `X:'a` + // is implied by the environment is done in regionck. + ty::view::Param(p) => { + out.push(Component::Param(p)); + } - // For projections, we prefer to generate an obligation like - // `>::Foo: 'a`, because this gives the - // regionck more ways to prove that it holds. However, - // regionck is not (at least currently) prepared to deal with - // higher-ranked regions that may appear in the - // trait-ref. Therefore, if we see any higher-ranke regions, - // we simply fallback to the most restrictive rule, which - // requires that `Pi: 'a` for all `i`. - ty::view::Projection(data) => { - if !data.has_escaping_bound_vars() { - // best case: no escaping regions, so push the - // projection and skip the subtree (thus generating no - // constraints for Pi). This defers the choice between - // the rules OutlivesProjectionEnv, - // OutlivesProjectionTraitDef, and - // OutlivesProjectionComponents to regionck. - out.push(Component::Projection(data)); - } else { - // fallback case: hard code - // OutlivesProjectionComponents. Continue walking - // through and constrain Pi. - let subcomponents = capture_components(tcx, ty); - out.push(Component::EscapingProjection(subcomponents)); - } + // For projections, we prefer to generate an obligation like + // `>::Foo: 'a`, because this gives the + // regionck more ways to prove that it holds. However, + // regionck is not (at least currently) prepared to deal with + // higher-ranked regions that may appear in the + // trait-ref. Therefore, if we see any higher-ranke regions, + // we simply fallback to the most restrictive rule, which + // requires that `Pi: 'a` for all `i`. + ty::view::Projection(data) => { + if !data.has_escaping_bound_vars() { + // best case: no escaping regions, so push the + // projection and skip the subtree (thus generating no + // constraints for Pi). This defers the choice between + // the rules OutlivesProjectionEnv, + // OutlivesProjectionTraitDef, and + // OutlivesProjectionComponents to regionck. + out.push(Component::Projection(data)); + } else { + // fallback case: hard code + // OutlivesProjectionComponents. Continue walking + // through and constrain Pi. + let subcomponents = capture_components(tcx, ty); + out.push(Component::EscapingProjection(subcomponents)); } + } - ty::view::UnnormalizedProjection(..) => bug!("only used with chalk-engine"), + ty::view::UnnormalizedProjection(..) => bug!("only used with chalk-engine"), - // We assume that inference variables are fully resolved. - // So, if we encounter an inference variable, just record - // the unresolved variable as a component. - ty::view::Infer(infer_ty) => { - out.push(Component::UnresolvedInferenceVariable(infer_ty)); - } + // We assume that inference variables are fully resolved. + // So, if we encounter an inference variable, just record + // the unresolved variable as a component. + ty::view::Infer(infer_ty) => { + out.push(Component::UnresolvedInferenceVariable(infer_ty)); + } - // Most types do not introduce any region binders, nor - // involve any other subtle cases, and so the WF relation - // simply constraints any regions referenced directly by - // the type and then visits the types that are lexically - // contained within. (The comments refer to relevant rules - // from RFC1214.) - ty::view::Bool | // OutlivesScalar - ty::view::Char | // OutlivesScalar - ty::view::Int(..) | // OutlivesScalar - ty::view::Uint(..) | // OutlivesScalar - ty::view::Float(..) | // OutlivesScalar - ty::view::Never | // ... - ty::view::Adt(..) | // OutlivesNominalType - ty::view::Opaque(..) | // OutlivesNominalType (ish) - ty::view::Foreign(..) | // OutlivesNominalType - ty::view::Str | // OutlivesScalar (ish) - ty::view::Array(..) | // ... - ty::view::Slice(..) | // ... - ty::view::RawPtr(..) | // ... - ty::view::Ref(..) | // OutlivesReference - ty::view::Tuple(..) | // ... - ty::view::FnDef(..) | // OutlivesFunction (*) - ty::view::FnPtr(_) | // OutlivesFunction (*) - ty::view::Dynamic(..) | // OutlivesObject, OutlivesFragment (*) - ty::view::Placeholder(..) | - ty::view::Bound(..) | - ty::view::Error => { - // (*) Bare functions and traits are both binders. In the - // RFC, this means we would add the bound regions to the - // "bound regions list". In our representation, no such - // list is maintained explicitly, because bound regions - // themselves can be readily identified. - - push_region_constraints(ty, out); - for subty in ty.walk_shallow() { - compute_components(tcx, subty, out); - } + // Most types do not introduce any region binders, nor + // involve any other subtle cases, and so the WF relation + // simply constraints any regions referenced directly by + // the type and then visits the types that are lexically + // contained within. (The comments refer to relevant rules + // from RFC1214.) + ty::view::Bool | // OutlivesScalar + ty::view::Char | // OutlivesScalar + ty::view::Int(..) | // OutlivesScalar + ty::view::Uint(..) | // OutlivesScalar + ty::view::Float(..) | // OutlivesScalar + ty::view::Never | // ... + ty::view::Adt(..) | // OutlivesNominalType + ty::view::Opaque(..) | // OutlivesNominalType (ish) + ty::view::Foreign(..) | // OutlivesNominalType + ty::view::Str | // OutlivesScalar (ish) + ty::view::Array(..) | // ... + ty::view::Slice(..) | // ... + ty::view::RawPtr(..) | // ... + ty::view::Ref(..) | // OutlivesReference + ty::view::Tuple(..) | // ... + ty::view::FnDef(..) | // OutlivesFunction (*) + ty::view::FnPtr(_) | // OutlivesFunction (*) + ty::view::Dynamic(..) | // OutlivesObject, OutlivesFragment (*) + ty::view::Placeholder(..) | + ty::view::Bound(..) | + ty::view::Error => { + // (*) Bare functions and traits are both binders. In the + // RFC, this means we would add the bound regions to the + // "bound regions list". In our representation, no such + // list is maintained explicitly, because bound regions + // themselves can be readily identified. + + push_region_constraints(ty, out); + for subty in ty.walk_shallow() { + compute_components(tcx, subty, out); } } + } } fn capture_components(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Vec> { diff --git a/src/librustc_data_structures/captures.rs b/src/librustc_data_structures/captures.rs index ea2452187ee97..1e90aa6945b2d 100644 --- a/src/librustc_data_structures/captures.rs +++ b/src/librustc_data_structures/captures.rs @@ -8,8 +8,3 @@ pub trait Captures<'a> {} impl Captures<'_> for T {} - -#[allow(unused_lifetimes)] -pub trait Captures2<'a, 'b> {} - -impl Captures2<'_, '_> for T {} From 98f302c2c20f9b8a135ac147538c7cd147b7d558 Mon Sep 17 00:00:00 2001 From: Markus Westerlind Date: Fri, 10 Jan 2020 11:52:28 +0100 Subject: [PATCH 6/8] View can use the faster hashing and equality checks on Ty instead of the inner type --- src/librustc/ty/view.rs | 31 ++----------------------------- 1 file changed, 2 insertions(+), 29 deletions(-) diff --git a/src/librustc/ty/view.rs b/src/librustc/ty/view.rs index 4cc96e842454f..e709c41f97930 100644 --- a/src/librustc/ty/view.rs +++ b/src/librustc/ty/view.rs @@ -1,8 +1,4 @@ -use std::{ - fmt, - hash::{Hash, Hasher}, - marker::PhantomData, -}; +use std::{fmt, marker::PhantomData}; use syntax::ast; @@ -17,35 +13,12 @@ pub use self::ViewKind::*; /// `View<'tcx, T>` contains a value of `T` but stores the `Ty<'tcx>` ptr that contains the `T` /// This allows for cheap access to the `Ty<'tcx>` without needing to ask the type interner or /// losing the `T` type. -#[derive(TypeFoldable, Lift)] +#[derive(TypeFoldable, Eq, PartialEq, Hash, Lift)] pub struct View<'tcx, T> { ty: Ty<'tcx>, _marker: PhantomData, } -impl<'tcx, T> PartialEq for View<'tcx, T> -where - T: PartialEq + TyDeref<'tcx>, -{ - fn eq(&self, other: &Self) -> bool { - **self == **other - } -} - -impl<'tcx, T> Eq for View<'tcx, T> where T: Eq + TyDeref<'tcx> {} - -impl<'tcx, T> Hash for View<'tcx, T> -where - T: Hash + TyDeref<'tcx>, -{ - fn hash(&self, hasher: &mut H) - where - H: Hasher, - { - (**self).hash(hasher) - } -} - impl Copy for View<'_, T> {} impl Clone for View<'_, T> { From 2eb5de74c246f629c0221a7be6d19108d4322783 Mon Sep 17 00:00:00 2001 From: Markus Westerlind Date: Sat, 18 Jan 2020 11:54:55 +0100 Subject: [PATCH 7/8] Add inline annotations to View --- src/librustc/ty/view.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/librustc/ty/view.rs b/src/librustc/ty/view.rs index e709c41f97930..33fa241d2678b 100644 --- a/src/librustc/ty/view.rs +++ b/src/librustc/ty/view.rs @@ -22,6 +22,7 @@ pub struct View<'tcx, T> { impl Copy for View<'_, T> {} impl Clone for View<'_, T> { + #[inline] fn clone(&self) -> Self { View { ty: self.ty, _marker: PhantomData } } @@ -49,6 +50,8 @@ where T: TyDeref<'tcx>, { type Target = T; + + #[inline] fn deref(&self) -> &Self::Target { match T::ty_deref(self.ty) { Some(t) => t, @@ -62,6 +65,7 @@ impl<'tcx, T> View<'tcx, T> where T: TyDeref<'tcx>, { + #[inline] pub fn new(ty: Ty<'tcx>) -> Option { T::ty_deref(ty)?; Some(View { ty, _marker: PhantomData }) @@ -69,6 +73,7 @@ where } impl<'tcx, T> View<'tcx, T> { + #[inline] pub fn as_ty(&self) -> Ty<'tcx> { self.ty } @@ -83,6 +88,7 @@ pub unsafe trait TyDeref<'tcx>: Sized + 'tcx { macro_rules! impl_ty_deref { ($ty: ty, $variant: ident) => { unsafe impl<'tcx> TyDeref<'tcx> for $ty { + #[inline] fn ty_deref(ty: Ty<'tcx>) -> Option<&'tcx Self> { match &ty.kind { ty::$variant(p) => Some(p), @@ -129,6 +135,7 @@ pub enum ViewKind<'tcx> { } impl<'tcx> From> for ViewKind<'tcx> { + #[inline] fn from(ty: Ty<'tcx>) -> Self { match ty.kind { ty::RawPtr(tm) => Self::RawPtr(tm), From 1214625038a68d0e8fa00dbd997c1d5735bf2b4c Mon Sep 17 00:00:00 2001 From: Markus Westerlind Date: Sat, 18 Jan 2020 12:12:17 +0100 Subject: [PATCH 8/8] Specialize Lift and TypeFoldable for View --- src/librustc/ty/view.rs | 48 ++++++++++++++++++++++++++++++++++++++--- 1 file changed, 45 insertions(+), 3 deletions(-) diff --git a/src/librustc/ty/view.rs b/src/librustc/ty/view.rs index 33fa241d2678b..8c5dfec7551b1 100644 --- a/src/librustc/ty/view.rs +++ b/src/librustc/ty/view.rs @@ -3,8 +3,11 @@ use std::{fmt, marker::PhantomData}; use syntax::ast; use crate::ty::{ - self, AdtDef, Binder, BoundTy, ExistentialPredicate, InferTy, List, ParamTy, PolyFnSig, - ProjectionTy, Region, SubstsRef, Ty, TypeAndMut, + self, + context::{Lift, TyCtxt}, + fold::{TypeFoldable, TypeFolder, TypeVisitor}, + AdtDef, Binder, BoundTy, ExistentialPredicate, InferTy, List, ParamTy, PolyFnSig, ProjectionTy, + Region, SubstsRef, Ty, TypeAndMut, }; use rustc_hir::{self as hir, def_id::DefId}; @@ -13,12 +16,39 @@ pub use self::ViewKind::*; /// `View<'tcx, T>` contains a value of `T` but stores the `Ty<'tcx>` ptr that contains the `T` /// This allows for cheap access to the `Ty<'tcx>` without needing to ask the type interner or /// losing the `T` type. -#[derive(TypeFoldable, Eq, PartialEq, Hash, Lift)] +#[derive(Eq, PartialEq, Hash)] pub struct View<'tcx, T> { ty: Ty<'tcx>, _marker: PhantomData, } +impl<'a, 'tcx, T> Lift<'tcx> for View<'a, T> +where + T: TyDeref<'a> + Lift<'tcx>, + T::Lifted: TyDeref<'tcx>, +{ + type Lifted = View<'tcx, T::Lifted>; + fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option { + tcx.lift(&**self).map(|t| View::intern(tcx, t)) + } +} + +impl<'tcx, T> TypeFoldable<'tcx> for View<'tcx, T> +where + T: TyDeref<'tcx> + TypeFoldable<'tcx> + PartialEq, +{ + fn super_fold_with>(&self, folder: &mut F) -> Self { + let tcx = folder.tcx(); + let old_t = &**self; + let new_t = old_t.super_fold_with(folder); + if *old_t == new_t { *self } else { Self::intern(tcx, new_t) } + } + + fn super_visit_with>(&self, visitor: &mut V) -> bool { + (**self).super_visit_with(visitor) + } +} + impl Copy for View<'_, T> {} impl Clone for View<'_, T> { @@ -70,6 +100,12 @@ where T::ty_deref(ty)?; Some(View { ty, _marker: PhantomData }) } + + #[inline] + pub fn intern(tcx: TyCtxt<'tcx>, t: T) -> Self { + let ty = t.intern(tcx); + View { ty, _marker: PhantomData } + } } impl<'tcx, T> View<'tcx, T> { @@ -82,12 +118,18 @@ impl<'tcx, T> View<'tcx, T> { /// SAFETY If `Some` is returned for `ty` then `Some` must always be returned for any subsequent /// call with the same `Ty` value pub unsafe trait TyDeref<'tcx>: Sized + 'tcx { + fn intern(self, tcx: TyCtxt<'tcx>) -> Ty<'tcx>; fn ty_deref(ty: Ty<'tcx>) -> Option<&'tcx Self>; } macro_rules! impl_ty_deref { ($ty: ty, $variant: ident) => { unsafe impl<'tcx> TyDeref<'tcx> for $ty { + #[inline] + fn intern(self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> { + tcx.mk_ty(ty::$variant(self)) + } + #[inline] fn ty_deref(ty: Ty<'tcx>) -> Option<&'tcx Self> { match &ty.kind {