]> git.lizzy.rs Git - rust.git/blobdiff - src/librustc/ty/util.rs
move projection mode into parameter environment
[rust.git] / src / librustc / ty / util.rs
index c6c6a0e47003dbb40777d056b2ade638c6259eb7..31c099c661df05d9a80a4f4ae3c90599e8c48324 100644 (file)
 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;
@@ -36,8 +33,6 @@
 use syntax::attr::{self, SignedInt, UnsignedInt};
 use syntax_pos::{Span, DUMMY_SP};
 
-use hir;
-
 type Disr = ConstInt;
 
 pub trait IntTypeExt {
@@ -152,12 +147,35 @@ pub enum Representability {
     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),
@@ -260,13 +278,29 @@ pub fn named_element_ty(self,
     /// 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
@@ -578,6 +612,15 @@ pub fn empty_substs_for_def_id(self, item_def_id: DefId) -> &'tcx ty::Substs<'tc
             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> {
@@ -660,8 +703,7 @@ fn visit_ty(&mut self, ty: Ty<'tcx>) -> bool {
                 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 |
@@ -711,152 +753,28 @@ fn visit_binder<T: TypeFoldable<'tcx>>(&mut self, x: &ty::Binder<T>) -> bool {
 }
 
 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),
-                              &param_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),
-                              &param_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),
-                              &param_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
@@ -866,112 +784,11 @@ fn is_freeze_uncached(&'tcx self, tcx: TyCtxt<'a, 'tcx, 'tcx>,
     /// (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]
@@ -1158,3 +975,112 @@ fn is_type_structurally_recursive<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
         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
+    };
+}