diff options
Diffstat (limited to 'src/librustc/ty/util.rs')
| -rw-r--r-- | src/librustc/ty/util.rs | 164 |
1 files changed, 117 insertions, 47 deletions
diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs index 27819f551b9..129badc46d8 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -10,14 +10,15 @@ //! misc. type-system utilities too small to deserve their own file +use hir::def::Def; use hir::def_id::{DefId, LOCAL_CRATE}; -use hir::map::DefPathData; +use hir::map::{DefPathData, Node}; +use hir; use ich::NodeIdHashingMode; use middle::const_val::ConstVal; use traits::{self, Reveal}; use ty::{self, Ty, TyCtxt, TypeFoldable}; use ty::fold::TypeVisitor; -use ty::layout::{Layout, LayoutError}; use ty::subst::{Subst, Kind}; use ty::TypeVariants::*; use util::common::ErrorReported; @@ -515,11 +516,11 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { let result = item_substs.iter().zip(impl_substs.iter()) .filter(|&(_, &k)| { if let Some(&ty::RegionKind::ReEarlyBound(ref ebr)) = k.as_region() { - !impl_generics.region_param(ebr).pure_wrt_drop + !impl_generics.region_param(ebr, self).pure_wrt_drop } else if let Some(&ty::TyS { sty: ty::TypeVariants::TyParam(ref pt), .. }) = k.as_type() { - !impl_generics.type_param(pt).pure_wrt_drop + !impl_generics.type_param(pt, self).pure_wrt_drop } else { // not a type or region param - this should be reported // as an error. @@ -553,7 +554,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { let result = match ty.sty { ty::TyBool | ty::TyChar | ty::TyInt(_) | ty::TyUint(_) | - ty::TyFloat(_) | ty::TyStr | ty::TyNever | + ty::TyFloat(_) | ty::TyStr | ty::TyNever | ty::TyForeign(..) | ty::TyRawPtr(..) | ty::TyRef(..) | ty::TyFnDef(..) | ty::TyFnPtr(_) => { // these types never have a destructor Ok(ty::DtorckConstraint::empty()) @@ -619,9 +620,20 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { result } + pub fn is_closure(self, def_id: DefId) -> bool { + self.def_key(def_id).disambiguated_data.data == DefPathData::ClosureExpr + } + + /// Given the `DefId` of a fn or closure, returns the `DefId` of + /// the innermost fn item that the closure is contained within. + /// This is a significant def-id because, when we do + /// type-checking, we type-check this fn item and all of its + /// (transitive) closures together. Therefore, when we fetch the + /// `typeck_tables_of` the closure, for example, we really wind up + /// fetching the `typeck_tables_of` the enclosing fn item. pub fn closure_base_def_id(self, def_id: DefId) -> DefId { let mut def_id = def_id; - while self.def_key(def_id).disambiguated_data.data == DefPathData::ClosureExpr { + while self.is_closure(def_id) { def_id = self.parent_def_id(def_id).unwrap_or_else(|| { bug!("closure {:?} has no parent", def_id); }); @@ -629,6 +641,33 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { def_id } + /// Given the def-id and substs a closure, creates the type of + /// `self` argument that the closure expects. For example, for a + /// `Fn` closure, this would return a reference type `&T` where + /// `T=closure_ty`. + /// + /// Returns `None` if this closure's kind has not yet been inferred. + /// This should only be possible during type checking. + /// + /// Note that the return value is a late-bound region and hence + /// wrapped in a binder. + pub fn closure_env_ty(self, + closure_def_id: DefId, + closure_substs: ty::ClosureSubsts<'tcx>) + -> Option<ty::Binder<Ty<'tcx>>> + { + let closure_ty = self.mk_closure(closure_def_id, closure_substs); + let env_region = ty::ReLateBound(ty::DebruijnIndex::new(1), ty::BrEnv); + let closure_kind_ty = closure_substs.closure_kind_ty(closure_def_id, self); + let closure_kind = closure_kind_ty.to_opt_closure_kind()?; + let env_ty = match closure_kind { + ty::ClosureKind::Fn => self.mk_imm_ref(self.mk_region(env_region), closure_ty), + ty::ClosureKind::FnMut => self.mk_mut_ref(self.mk_region(env_region), closure_ty), + ty::ClosureKind::FnOnce => closure_ty, + }; + Some(ty::Binder(env_ty)) + } + /// Given the def-id of some item that has no type parameters, make /// a suitable "empty substs" for it. pub fn empty_substs_for_def_id(self, item_def_id: DefId) -> &'tcx ty::Substs<'tcx> { @@ -647,6 +686,26 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { _ => bug!(), } } + + /// Check if the node pointed to by def_id is a mutable static item + pub fn is_static_mut(&self, def_id: DefId) -> bool { + if let Some(node) = self.hir.get_if_local(def_id) { + match node { + Node::NodeItem(&hir::Item { + node: hir::ItemStatic(_, hir::MutMutable, _), .. + }) => true, + Node::NodeForeignItem(&hir::ForeignItem { + node: hir::ForeignItemStatic(_, mutbl), .. + }) => mutbl, + _ => false + } + } else { + match self.describe_def(def_id) { + Some(Def::Static(_, mutbl)) => mutbl, + _ => false + } + } + } } pub struct TypeIdHasher<'a, 'gcx: 'a+'tcx, 'tcx: 'a, W> { @@ -714,6 +773,7 @@ impl<'a, 'gcx, 'tcx, W> TypeVisitor<'tcx> for TypeIdHasher<'a, 'gcx, 'tcx, W> TyAnon(def_id, _) | TyFnDef(def_id, _) => self.def_id(def_id), TyAdt(d, _) => self.def_id(d.did), + TyForeign(def_id) => self.def_id(def_id), TyFnPtr(f) => { self.hash(f.unsafety()); self.hash(f.abi()); @@ -825,30 +885,6 @@ impl<'a, 'tcx> ty::TyS<'tcx> { tcx.needs_drop_raw(param_env.and(self)) } - /// Computes the layout of a type. Note that this implicitly - /// executes in "reveal all" mode. - #[inline] - pub fn layout<'lcx>(&'tcx self, - tcx: TyCtxt<'a, 'tcx, 'tcx>, - param_env: ty::ParamEnv<'tcx>) - -> Result<&'tcx Layout, LayoutError<'tcx>> { - let ty = tcx.erase_regions(&self); - let layout = tcx.layout_raw(param_env.reveal_all().and(ty)); - - // NB: This recording is normally disabled; when enabled, it - // can however trigger recursive invocations of `layout()`. - // Therefore, we execute it *after* the main query has - // completed, to avoid problems around recursive structures - // and the like. (Admitedly, I wasn't able to reproduce a problem - // here, but it seems like the right thing to do. -nmatsakis) - if let Ok(l) = layout { - Layout::record_layout_for_printing(tcx, ty, param_env, l); - } - - layout - } - - /// Check whether a type is representable. This means it cannot contain unboxed /// structural recursion. This check is needed for structs and enums. pub fn is_representable(&'tcx self, @@ -1109,6 +1145,9 @@ fn needs_drop_raw<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, ty::TyFnDef(..) | ty::TyFnPtr(_) | ty::TyChar | ty::TyRawPtr(_) | ty::TyRef(..) | ty::TyStr => false, + // Foreign types can never have destructors + ty::TyForeign(..) => false, + // Issue #22536: We first query type_moves_by_default. It sees a // normalized version of the type, and therefore will definitely // know whether the type implements Copy (and thus needs no @@ -1154,24 +1193,56 @@ fn needs_drop_raw<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } } -fn layout_raw<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) - -> Result<&'tcx Layout, LayoutError<'tcx>> -{ - let (param_env, ty) = query.into_parts(); - - let rec_limit = tcx.sess.recursion_limit.get(); - let depth = tcx.layout_depth.get(); - if depth > rec_limit { - tcx.sess.fatal( - &format!("overflow representing the type `{}`", ty)); - } +pub enum ExplicitSelf<'tcx> { + ByValue, + ByReference(ty::Region<'tcx>, hir::Mutability), + ByBox, + Other +} - tcx.layout_depth.set(depth+1); - let layout = Layout::compute_uncached(tcx, param_env, ty); - tcx.layout_depth.set(depth); +impl<'tcx> ExplicitSelf<'tcx> { + /// Categorizes an explicit self declaration like `self: SomeType` + /// into either `self`, `&self`, `&mut self`, `Box<self>`, or + /// `Other`. + /// This is mainly used to require the arbitrary_self_types feature + /// in the case of `Other`, to improve error messages in the common cases, + /// and to make `Other` non-object-safe. + /// + /// Examples: + /// + /// ``` + /// impl<'a> Foo for &'a T { + /// // Legal declarations: + /// fn method1(self: &&'a T); // ExplicitSelf::ByReference + /// fn method2(self: &'a T); // ExplicitSelf::ByValue + /// fn method3(self: Box<&'a T>); // ExplicitSelf::ByBox + /// fn method4(self: Rc<&'a T>); // ExplicitSelf::Other + /// + /// // Invalid cases will be caught by `check_method_receiver`: + /// fn method_err1(self: &'a mut T); // ExplicitSelf::Other + /// fn method_err2(self: &'static T) // ExplicitSelf::ByValue + /// fn method_err3(self: &&T) // ExplicitSelf::ByReference + /// } + /// ``` + /// + pub fn determine<P>( + self_arg_ty: Ty<'tcx>, + is_self_ty: P + ) -> ExplicitSelf<'tcx> + where + P: Fn(Ty<'tcx>) -> bool + { + use self::ExplicitSelf::*; - layout + match self_arg_ty.sty { + _ if is_self_ty(self_arg_ty) => ByValue, + ty::TyRef(region, ty::TypeAndMut { ty, mutbl}) if is_self_ty(ty) => { + ByReference(region, mutbl) + } + ty::TyAdt(def, _) if def.is_box() && is_self_ty(self_arg_ty.boxed_ty()) => ByBox, + _ => Other + } + } } pub fn provide(providers: &mut ty::maps::Providers) { @@ -1180,7 +1251,6 @@ pub fn provide(providers: &mut ty::maps::Providers) { is_sized_raw, is_freeze_raw, needs_drop_raw, - layout_raw, ..*providers }; } |
