use infer::InferCtxt;
use ich::{StableHashingContext, NodeIdHashingMode};
use traits::{self, Reveal};
-use ty::{self, Ty, TyCtxt, TypeAndMut, TypeFlags, TypeFoldable};
-use ty::ParameterEnvironment;
+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;
-use util::nodemap::{FxHashMap, FxHashSet};
use middle::lang_items;
use rustc_const_math::{ConstInt, ConstIsize, ConstUsize};
use rustc_data_structures::stable_hasher::{StableHasher, StableHasherResult,
HashStable};
-use std::cell::RefCell;
use std::cmp;
use std::hash::Hash;
use std::intrinsics;
use syntax::attr::{self, SignedInt, UnsignedInt};
use syntax_pos::{Span, DUMMY_SP};
-use hir;
-
type Disr = ConstInt;
pub trait IntTypeExt {
SelfRecursive(Vec<Span>),
}
-impl<'tcx> ParameterEnvironment<'tcx> {
+impl<'tcx> ty::ParamEnv<'tcx> {
+ /// Construct a trait environment suitable for contexts where
+ /// there are no where clauses in scope.
+ pub fn empty(reveal: Reveal) -> Self {
+ Self::new(ty::Slice::empty(), reveal)
+ }
+
+ /// Construct a trait environment with the given set of predicates.
+ pub fn new(caller_bounds: &'tcx ty::Slice<ty::Predicate<'tcx>>,
+ reveal: Reveal)
+ -> Self {
+ ty::ParamEnv { caller_bounds, reveal }
+ }
+
+ /// Returns a new parameter environment with the same clauses, but
+ /// which "reveals" the true results of projections in all cases
+ /// (even for associated types that are specializable). This is
+ /// the desired behavior during trans and certain other special
+ /// contexts; normally though we want to use `Reveal::UserFacing`,
+ /// which is the default.
+ pub fn reveal_all(self) -> Self {
+ ty::ParamEnv { reveal: Reveal::All, ..self }
+ }
+
pub fn can_type_implement_copy<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>,
self_type: Ty<'tcx>, span: Span)
-> Result<(), CopyImplementationError> {
// FIXME: (@jroesch) float this code up
- tcx.infer_ctxt(self.clone(), Reveal::UserFacing).enter(|infcx| {
+ tcx.infer_ctxt(self.clone()).enter(|infcx| {
let (adt, substs) = match self_type.sty {
ty::TyAdt(adt, substs) => (adt, substs),
_ => return Err(CopyImplementationError::NotAnAdt),
/// if not a structure at all. Corresponds to the only possible unsized
/// field, and its type can be used to determine unsizing strategy.
pub fn struct_tail(self, mut ty: Ty<'tcx>) -> Ty<'tcx> {
- while let TyAdt(def, substs) = ty.sty {
- if !def.is_struct() {
- break;
- }
- match def.struct_variant().fields.last() {
- Some(f) => ty = f.ty(self, substs),
- None => break,
+ loop {
+ match ty.sty {
+ ty::TyAdt(def, substs) => {
+ if !def.is_struct() {
+ break;
+ }
+ match def.struct_variant().fields.last() {
+ Some(f) => ty = f.ty(self, substs),
+ None => break,
+ }
+ }
+
+ ty::TyTuple(tys, _) => {
+ if let Some((&last_ty, _)) = tys.split_last() {
+ ty = last_ty;
+ } else {
+ break;
+ }
+ }
+
+ _ => {
+ break;
+ }
}
}
ty
bug!("empty_substs_for_def_id: {:?} has type parameters", item_def_id)
})
}
+
+ pub fn const_usize(&self, val: u16) -> ConstInt {
+ match self.sess.target.uint_type {
+ ast::UintTy::U16 => ConstInt::Usize(ConstUsize::Us16(val as u16)),
+ ast::UintTy::U32 => ConstInt::Usize(ConstUsize::Us32(val as u32)),
+ ast::UintTy::U64 => ConstInt::Usize(ConstUsize::Us64(val as u64)),
+ _ => bug!(),
+ }
+ }
}
pub struct TypeIdHasher<'a, 'gcx: 'a+'tcx, 'tcx: 'a, W> {
self.hash(p.name.as_str());
}
TyProjection(ref data) => {
- self.def_id(data.trait_ref.def_id);
- self.hash(data.item_name.as_str());
+ self.def_id(data.item_def_id);
}
TyNever |
TyBool |
}
impl<'a, 'tcx> ty::TyS<'tcx> {
- fn impls_bound(&'tcx self, tcx: TyCtxt<'a, 'tcx, 'tcx>,
- param_env: &ParameterEnvironment<'tcx>,
- def_id: DefId,
- cache: &RefCell<FxHashMap<Ty<'tcx>, bool>>,
- span: Span) -> bool
- {
- if self.has_param_types() || self.has_self_ty() {
- if let Some(result) = cache.borrow().get(self) {
- return *result;
- }
- }
- let result =
- tcx.infer_ctxt(param_env.clone(), Reveal::UserFacing)
- .enter(|infcx| {
- traits::type_known_to_meet_bound(&infcx, self, def_id, span)
- });
- if self.has_param_types() || self.has_self_ty() {
- cache.borrow_mut().insert(self, result);
- }
- return result;
- }
-
- // FIXME (@jroesch): I made this public to use it, not sure if should be private
- pub fn moves_by_default(&'tcx self, tcx: TyCtxt<'a, 'tcx, 'tcx>,
- param_env: &ParameterEnvironment<'tcx>,
- span: Span) -> bool {
- if self.flags.get().intersects(TypeFlags::MOVENESS_CACHED) {
- return self.flags.get().intersects(TypeFlags::MOVES_BY_DEFAULT);
- }
-
- assert!(!self.needs_infer());
-
- // Fast-path for primitive types
- let result = match self.sty {
- TyBool | TyChar | TyInt(..) | TyUint(..) | TyFloat(..) | TyNever |
- TyRawPtr(..) | TyFnDef(..) | TyFnPtr(_) | TyRef(_, TypeAndMut {
- mutbl: hir::MutImmutable, ..
- }) => Some(false),
-
- TyStr | TyRef(_, TypeAndMut {
- mutbl: hir::MutMutable, ..
- }) => Some(true),
-
- TyArray(..) | TySlice(..) | TyDynamic(..) | TyTuple(..) |
- TyClosure(..) | TyAdt(..) | TyAnon(..) |
- TyProjection(..) | TyParam(..) | TyInfer(..) | TyError => None
- }.unwrap_or_else(|| {
- !self.impls_bound(tcx, param_env,
- tcx.require_lang_item(lang_items::CopyTraitLangItem),
- ¶m_env.is_copy_cache, span) });
-
- if !self.has_param_types() && !self.has_self_ty() {
- self.flags.set(self.flags.get() | if result {
- TypeFlags::MOVENESS_CACHED | TypeFlags::MOVES_BY_DEFAULT
- } else {
- TypeFlags::MOVENESS_CACHED
- });
- }
-
- result
+ pub fn moves_by_default(&'tcx self,
+ tcx: TyCtxt<'a, 'tcx, 'tcx>,
+ param_env: ty::ParamEnv<'tcx>,
+ span: Span)
+ -> bool {
+ !tcx.at(span).is_copy_raw(param_env.and(self))
}
- #[inline]
- pub fn is_sized(&'tcx self, tcx: TyCtxt<'a, 'tcx, 'tcx>,
- param_env: &ParameterEnvironment<'tcx>,
- span: Span) -> bool
+ pub fn is_sized(&'tcx self,
+ tcx: TyCtxt<'a, 'tcx, 'tcx>,
+ param_env: ty::ParamEnv<'tcx>,
+ span: Span)-> bool
{
- if self.flags.get().intersects(TypeFlags::SIZEDNESS_CACHED) {
- return self.flags.get().intersects(TypeFlags::IS_SIZED);
- }
-
- self.is_sized_uncached(tcx, param_env, span)
- }
-
- fn is_sized_uncached(&'tcx self, tcx: TyCtxt<'a, 'tcx, 'tcx>,
- param_env: &ParameterEnvironment<'tcx>,
- span: Span) -> bool {
- assert!(!self.needs_infer());
-
- // Fast-path for primitive types
- let result = match self.sty {
- TyBool | TyChar | TyInt(..) | TyUint(..) | TyFloat(..) |
- TyRawPtr(..) | TyRef(..) | TyFnDef(..) | TyFnPtr(_) |
- TyArray(..) | TyTuple(..) | TyClosure(..) | TyNever => Some(true),
-
- TyStr | TyDynamic(..) | TySlice(_) => Some(false),
-
- TyAdt(..) | TyProjection(..) | TyParam(..) |
- TyInfer(..) | TyAnon(..) | TyError => None
- }.unwrap_or_else(|| {
- self.impls_bound(tcx, param_env, tcx.require_lang_item(lang_items::SizedTraitLangItem),
- ¶m_env.is_sized_cache, span) });
-
- if !self.has_param_types() && !self.has_self_ty() {
- self.flags.set(self.flags.get() | if result {
- TypeFlags::SIZEDNESS_CACHED | TypeFlags::IS_SIZED
- } else {
- TypeFlags::SIZEDNESS_CACHED
- });
- }
-
- result
+ tcx.at(span).is_sized_raw(param_env.and(self))
}
- /// Returns `true` if and only if there are no `UnsafeCell`s
- /// nested within the type (ignoring `PhantomData` or pointers).
- #[inline]
- pub fn is_freeze(&'tcx self, tcx: TyCtxt<'a, 'tcx, 'tcx>,
- param_env: &ParameterEnvironment<'tcx>,
- span: Span) -> bool
+ pub fn is_freeze(&'tcx self,
+ tcx: TyCtxt<'a, 'tcx, 'tcx>,
+ param_env: ty::ParamEnv<'tcx>,
+ span: Span)-> bool
{
- if self.flags.get().intersects(TypeFlags::FREEZENESS_CACHED) {
- return self.flags.get().intersects(TypeFlags::IS_FREEZE);
- }
-
- self.is_freeze_uncached(tcx, param_env, span)
- }
-
- fn is_freeze_uncached(&'tcx self, tcx: TyCtxt<'a, 'tcx, 'tcx>,
- param_env: &ParameterEnvironment<'tcx>,
- span: Span) -> bool {
- assert!(!self.needs_infer());
-
- // Fast-path for primitive types
- let result = match self.sty {
- TyBool | TyChar | TyInt(..) | TyUint(..) | TyFloat(..) |
- TyRawPtr(..) | TyRef(..) | TyFnDef(..) | TyFnPtr(_) |
- TyStr | TyNever => Some(true),
-
- TyArray(..) | TySlice(_) |
- TyTuple(..) | TyClosure(..) | TyAdt(..) |
- TyDynamic(..) | TyProjection(..) | TyParam(..) |
- TyInfer(..) | TyAnon(..) | TyError => None
- }.unwrap_or_else(|| {
- self.impls_bound(tcx, param_env, tcx.require_lang_item(lang_items::FreezeTraitLangItem),
- ¶m_env.is_freeze_cache, span) });
-
- if !self.has_param_types() && !self.has_self_ty() {
- self.flags.set(self.flags.get() | if result {
- TypeFlags::FREEZENESS_CACHED | TypeFlags::IS_FREEZE
- } else {
- TypeFlags::FREEZENESS_CACHED
- });
- }
-
- result
+ tcx.at(span).is_freeze_raw(param_env.and(self))
}
/// If `ty.needs_drop(...)` returns `true`, then `ty` is definitely
/// (Note that this implies that if `ty` has a destructor attached,
/// then `needs_drop` will definitely return `true` for `ty`.)
#[inline]
- pub fn needs_drop(&'tcx self, tcx: TyCtxt<'a, 'tcx, 'tcx>,
- param_env: &ty::ParameterEnvironment<'tcx>) -> bool {
- if self.flags.get().intersects(TypeFlags::NEEDS_DROP_CACHED) {
- return self.flags.get().intersects(TypeFlags::NEEDS_DROP);
- }
-
- self.needs_drop_uncached(tcx, param_env, &mut FxHashSet())
- }
-
- fn needs_drop_inner(&'tcx self,
- tcx: TyCtxt<'a, 'tcx, 'tcx>,
- param_env: &ty::ParameterEnvironment<'tcx>,
- stack: &mut FxHashSet<Ty<'tcx>>)
- -> bool {
- if self.flags.get().intersects(TypeFlags::NEEDS_DROP_CACHED) {
- return self.flags.get().intersects(TypeFlags::NEEDS_DROP);
- }
-
- // This should be reported as an error by `check_representable`.
- //
- // Consider the type as not needing drop in the meanwhile to avoid
- // further errors.
- if let Some(_) = stack.replace(self) {
- return false;
- }
-
- let needs_drop = self.needs_drop_uncached(tcx, param_env, stack);
-
- // "Pop" the cycle detection "stack".
- stack.remove(self);
-
- needs_drop
- }
-
- fn needs_drop_uncached(&'tcx self,
- tcx: TyCtxt<'a, 'tcx, 'tcx>,
- param_env: &ty::ParameterEnvironment<'tcx>,
- stack: &mut FxHashSet<Ty<'tcx>>)
- -> bool {
- assert!(!self.needs_infer());
-
- let result = match self.sty {
- // Fast-path for primitive types
- ty::TyInfer(ty::FreshIntTy(_)) | ty::TyInfer(ty::FreshFloatTy(_)) |
- ty::TyBool | ty::TyInt(_) | ty::TyUint(_) | ty::TyFloat(_) | ty::TyNever |
- ty::TyFnDef(..) | ty::TyFnPtr(_) | ty::TyChar |
- ty::TyRawPtr(_) | ty::TyRef(..) | ty::TyStr => 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
- // cleanup/drop/zeroing) ...
- _ if !self.moves_by_default(tcx, param_env, DUMMY_SP) => false,
-
- // ... (issue #22536 continued) but as an optimization, still use
- // prior logic of asking for the structural "may drop".
-
- // FIXME(#22815): Note that this is a conservative heuristic;
- // it may report that the type "may drop" when actual type does
- // not actually have a destructor associated with it. But since
- // the type absolutely did not have the `Copy` bound attached
- // (see above), it is sound to treat it as having a destructor.
-
- // User destructors are the only way to have concrete drop types.
- ty::TyAdt(def, _) if def.has_dtor(tcx) => true,
-
- // Can refer to a type which may drop.
- // FIXME(eddyb) check this against a ParameterEnvironment.
- ty::TyDynamic(..) | ty::TyProjection(..) | ty::TyParam(_) |
- ty::TyAnon(..) | ty::TyInfer(_) | ty::TyError => true,
-
- // Structural recursion.
- ty::TyArray(ty, _) | ty::TySlice(ty) => {
- ty.needs_drop_inner(tcx, param_env, stack)
- }
-
- ty::TyClosure(def_id, ref substs) => {
- substs.upvar_tys(def_id, tcx)
- .any(|ty| ty.needs_drop_inner(tcx, param_env, stack))
- }
-
- ty::TyTuple(ref tys, _) => {
- tys.iter().any(|ty| ty.needs_drop_inner(tcx, param_env, stack))
- }
-
- // unions don't have destructors regardless of the child types
- ty::TyAdt(def, _) if def.is_union() => false,
-
- ty::TyAdt(def, substs) => {
- def.variants.iter().any(|v| {
- v.fields.iter().any(|f| {
- f.ty(tcx, substs).needs_drop_inner(tcx, param_env, stack)
- })
- })
- }
- };
-
- if !self.has_param_types() && !self.has_self_ty() {
- self.flags.set(self.flags.get() | if result {
- TypeFlags::NEEDS_DROP_CACHED | TypeFlags::NEEDS_DROP
- } else {
- TypeFlags::NEEDS_DROP_CACHED
- });
- }
-
- result
+ pub fn needs_drop(&'tcx self,
+ tcx: TyCtxt<'a, 'tcx, 'tcx>,
+ param_env: ty::ParamEnv<'tcx>)
+ -> bool {
+ tcx.needs_drop_raw(param_env.and(self))
}
#[inline]
r
}
}
+
+fn is_copy_raw<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+ query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>)
+ -> bool
+{
+ let (param_env, ty) = query.into_parts();
+ let trait_def_id = tcx.require_lang_item(lang_items::CopyTraitLangItem);
+ tcx.infer_ctxt(param_env)
+ .enter(|infcx| traits::type_known_to_meet_bound(&infcx, ty, trait_def_id, DUMMY_SP))
+}
+
+fn is_sized_raw<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+ query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>)
+ -> bool
+{
+ let (param_env, ty) = query.into_parts();
+ let trait_def_id = tcx.require_lang_item(lang_items::SizedTraitLangItem);
+ tcx.infer_ctxt(param_env)
+ .enter(|infcx| traits::type_known_to_meet_bound(&infcx, ty, trait_def_id, DUMMY_SP))
+}
+
+fn is_freeze_raw<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+ query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>)
+ -> bool
+{
+ let (param_env, ty) = query.into_parts();
+ let trait_def_id = tcx.require_lang_item(lang_items::FreezeTraitLangItem);
+ tcx.infer_ctxt(param_env)
+ .enter(|infcx| traits::type_known_to_meet_bound(&infcx, ty, trait_def_id, DUMMY_SP))
+}
+
+fn needs_drop_raw<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+ query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>)
+ -> bool
+{
+ let (param_env, ty) = query.into_parts();
+
+ let needs_drop = |ty: Ty<'tcx>| -> bool {
+ match ty::queries::needs_drop_raw::try_get(tcx, DUMMY_SP, param_env.and(ty)) {
+ Ok(v) => v,
+ Err(_) => {
+ // Cycles should be reported as an error by `check_representable`.
+ //
+ // Consider the type as not needing drop in the meanwhile to avoid
+ // further errors.
+ false
+ }
+ }
+ };
+
+ assert!(!ty.needs_infer());
+
+ match ty.sty {
+ // Fast-path for primitive types
+ ty::TyInfer(ty::FreshIntTy(_)) | ty::TyInfer(ty::FreshFloatTy(_)) |
+ ty::TyBool | ty::TyInt(_) | ty::TyUint(_) | ty::TyFloat(_) | ty::TyNever |
+ ty::TyFnDef(..) | ty::TyFnPtr(_) | ty::TyChar |
+ ty::TyRawPtr(_) | ty::TyRef(..) | ty::TyStr => 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
+ // cleanup/drop/zeroing) ...
+ _ if !ty.moves_by_default(tcx, param_env, DUMMY_SP) => false,
+
+ // ... (issue #22536 continued) but as an optimization, still use
+ // prior logic of asking for the structural "may drop".
+
+ // FIXME(#22815): Note that this is a conservative heuristic;
+ // it may report that the type "may drop" when actual type does
+ // not actually have a destructor associated with it. But since
+ // the type absolutely did not have the `Copy` bound attached
+ // (see above), it is sound to treat it as having a destructor.
+
+ // User destructors are the only way to have concrete drop types.
+ ty::TyAdt(def, _) if def.has_dtor(tcx) => true,
+
+ // Can refer to a type which may drop.
+ // FIXME(eddyb) check this against a ParamEnv.
+ ty::TyDynamic(..) | ty::TyProjection(..) | ty::TyParam(_) |
+ ty::TyAnon(..) | ty::TyInfer(_) | ty::TyError => true,
+
+ // Structural recursion.
+ ty::TyArray(ty, _) | ty::TySlice(ty) => needs_drop(ty),
+
+ ty::TyClosure(def_id, ref substs) => substs.upvar_tys(def_id, tcx).any(needs_drop),
+
+ ty::TyTuple(ref tys, _) => tys.iter().cloned().any(needs_drop),
+
+ // unions don't have destructors regardless of the child types
+ ty::TyAdt(def, _) if def.is_union() => false,
+
+ ty::TyAdt(def, substs) =>
+ def.variants.iter().any(
+ |variant| variant.fields.iter().any(
+ |field| needs_drop(field.ty(tcx, substs)))),
+ }
+}
+
+
+pub fn provide(providers: &mut ty::maps::Providers) {
+ *providers = ty::maps::Providers {
+ is_copy_raw,
+ is_sized_raw,
+ is_freeze_raw,
+ needs_drop_raw,
+ ..*providers
+ };
+}