Shrink ParamEnv to 16 bytes

This commit is contained in:
Mark Rousskov 2020-07-02 20:52:40 -04:00
parent 3503f565e1
commit aae1215f7f
24 changed files with 187 additions and 83 deletions

View file

@ -11,7 +11,7 @@ pub fn explicit_outlives_bounds<'tcx>(
param_env: ty::ParamEnv<'tcx>,
) -> impl Iterator<Item = OutlivesBound<'tcx>> + 'tcx {
debug!("explicit_outlives_bounds()");
param_env.caller_bounds.into_iter().filter_map(move |predicate| match predicate.kind() {
param_env.caller_bounds().into_iter().filter_map(move |predicate| match predicate.kind() {
ty::PredicateKind::Projection(..)
| ty::PredicateKind::Trait(..)
| ty::PredicateKind::Subtype(..)

View file

@ -221,7 +221,7 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> {
// dubious for projections, but it will work for simple cases
// like `T` and `T::Item`. It may not work as well for things
// like `<T as Foo<'a>>::Item`.
let c_b = self.param_env.caller_bounds;
let c_b = self.param_env.caller_bounds();
let param_bounds = self.collect_outlives_from_predicate_list(&compare_ty, c_b.into_iter());
// Next, collect regions we scraped from the well-formedness

View file

@ -57,7 +57,7 @@ pub type TraitObligation<'tcx> = Obligation<'tcx, ty::PolyTraitPredicate<'tcx>>;
// `PredicateObligation` is used a lot. Make sure it doesn't unintentionally get bigger.
#[cfg(target_arch = "x86_64")]
static_assert_size!(PredicateObligation<'_>, 48);
static_assert_size!(PredicateObligation<'_>, 40);
pub type Obligations<'tcx, O> = Vec<Obligation<'tcx, O>>;
pub type PredicateObligations<'tcx> = Vec<PredicateObligation<'tcx>>;

View file

@ -1588,7 +1588,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
// Ignore layouts that are done with non-empty environments or
// non-monomorphic layouts, as the user only wants to see the stuff
// resulting from the final codegen session.
if layout.ty.has_param_types_or_consts() || !self.param_env.caller_bounds.is_empty() {
if layout.ty.has_param_types_or_consts() || !self.param_env.caller_bounds().is_empty() {
return;
}

View file

@ -1,3 +1,5 @@
// ignore-tidy-filelength
pub use self::fold::{TypeFoldable, TypeVisitor};
pub use self::AssocItemContainer::*;
pub use self::BorrowKind::*;
@ -45,6 +47,7 @@ use std::cell::RefCell;
use std::cmp::Ordering;
use std::fmt;
use std::hash::{Hash, Hasher};
use std::marker::PhantomData;
use std::ops::Range;
use std::ptr;
@ -1571,17 +1574,34 @@ pub type PlaceholderConst = Placeholder<BoundVar>;
/// When type checking, we use the `ParamEnv` to track
/// details about the set of where-clauses that are in scope at this
/// particular point.
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, HashStable, TypeFoldable)]
#[derive(Copy, Clone)]
pub struct ParamEnv<'tcx> {
// We pack the caller_bounds List pointer and a Reveal enum into this usize.
// Specifically, the low bit represents Reveal, with 0 meaning `UserFacing`
// and 1 meaning `All`. The rest is the pointer.
//
// This relies on the List<ty::Predicate<'tcx>> type having at least 2-byte
// alignment. Lists start with a usize and are repr(C) so this should be
// fine; there is a debug_assert in the constructor as well.
//
// Note that the choice of 0 for UserFacing is intentional -- since it is the
// first variant in Reveal this means that joining the pointer is a simple `or`.
packed_data: usize,
/// `Obligation`s that the caller must satisfy. This is basically
/// the set of bounds on the in-scope type parameters, translated
/// into `Obligation`s, and elaborated and normalized.
pub caller_bounds: &'tcx List<ty::Predicate<'tcx>>,
///
/// Note: This is packed into the `packed_data` usize above, use the
/// `caller_bounds()` method to access it.
caller_bounds: PhantomData<&'tcx List<ty::Predicate<'tcx>>>,
/// Typically, this is `Reveal::UserFacing`, but during codegen we
/// want `Reveal::All` -- note that this is always paired with an
/// empty environment. To get that, use `ParamEnv::reveal()`.
pub reveal: traits::Reveal,
/// want `Reveal::All`.
///
/// Note: This is packed into the caller_bounds usize above, use the reveal()
/// method to access it.
reveal: PhantomData<traits::Reveal>,
/// If this `ParamEnv` comes from a call to `tcx.param_env(def_id)`,
/// register that `def_id` (useful for transitioning to the chalk trait
@ -1589,6 +1609,57 @@ pub struct ParamEnv<'tcx> {
pub def_id: Option<DefId>,
}
impl<'tcx> fmt::Debug for ParamEnv<'tcx> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("ParamEnv")
.field("caller_bounds", &self.caller_bounds())
.field("reveal", &self.reveal())
.field("def_id", &self.def_id)
.finish()
}
}
impl<'tcx> Hash for ParamEnv<'tcx> {
fn hash<H: Hasher>(&self, state: &mut H) {
self.caller_bounds().hash(state);
self.reveal().hash(state);
self.def_id.hash(state);
}
}
impl<'tcx> PartialEq for ParamEnv<'tcx> {
fn eq(&self, other: &Self) -> bool {
self.caller_bounds() == other.caller_bounds()
&& self.reveal() == other.reveal()
&& self.def_id == other.def_id
}
}
impl<'tcx> Eq for ParamEnv<'tcx> {}
impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for ParamEnv<'tcx> {
fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
self.caller_bounds().hash_stable(hcx, hasher);
self.reveal().hash_stable(hcx, hasher);
self.def_id.hash_stable(hcx, hasher);
}
}
impl<'tcx> TypeFoldable<'tcx> for ParamEnv<'tcx> {
fn super_fold_with<F: ty::fold::TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
ParamEnv::new(
self.caller_bounds().fold_with(folder),
self.reveal().fold_with(folder),
self.def_id.fold_with(folder),
)
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
self.caller_bounds().visit_with(visitor)
|| self.reveal().visit_with(visitor)
|| self.def_id.visit_with(visitor)
}
}
impl<'tcx> ParamEnv<'tcx> {
/// Construct a trait environment suitable for contexts where
/// there are no where-clauses in scope. Hidden types (like `impl
@ -1599,6 +1670,17 @@ impl<'tcx> ParamEnv<'tcx> {
Self::new(List::empty(), Reveal::UserFacing, None)
}
#[inline]
pub fn caller_bounds(self) -> &'tcx List<ty::Predicate<'tcx>> {
// mask out bottom bit
unsafe { &*((self.packed_data & (!1)) as *const _) }
}
#[inline]
pub fn reveal(self) -> traits::Reveal {
if self.packed_data & 1 == 0 { traits::Reveal::UserFacing } else { traits::Reveal::All }
}
/// Construct a trait environment with no where-clauses in scope
/// where the values of all `impl Trait` and other hidden types
/// are revealed. This is suitable for monomorphized, post-typeck
@ -1618,7 +1700,25 @@ impl<'tcx> ParamEnv<'tcx> {
reveal: Reveal,
def_id: Option<DefId>,
) -> Self {
ty::ParamEnv { caller_bounds, reveal, def_id }
let packed_data = caller_bounds as *const _ as usize;
// Check that we can pack the reveal data into the pointer.
debug_assert!(packed_data & 1 == 0);
ty::ParamEnv {
packed_data: packed_data
| match reveal {
Reveal::UserFacing => 0,
Reveal::All => 1,
},
caller_bounds: PhantomData,
reveal: PhantomData,
def_id,
}
}
pub fn with_user_facing(mut self) -> Self {
// clear bottom bit
self.packed_data &= !1;
self
}
/// Returns a new parameter environment with the same clauses, but
@ -1627,13 +1727,14 @@ impl<'tcx> ParamEnv<'tcx> {
/// the desired behavior during codegen and certain other special
/// contexts; normally though we want to use `Reveal::UserFacing`,
/// which is the default.
pub fn with_reveal_all(self) -> Self {
ty::ParamEnv { reveal: Reveal::All, ..self }
pub fn with_reveal_all(mut self) -> Self {
self.packed_data |= 1;
self
}
/// Returns this same environment but with no caller bounds.
pub fn without_caller_bounds(self) -> Self {
ty::ParamEnv { caller_bounds: List::empty(), ..self }
Self::new(List::empty(), self.reveal(), self.def_id)
}
/// Creates a suitable environment in which to perform trait
@ -1649,7 +1750,7 @@ impl<'tcx> ParamEnv<'tcx> {
/// satisfiable. We generally want to behave as if they were true,
/// although the surrounding function is never reachable.
pub fn and<T: TypeFoldable<'tcx>>(self, value: T) -> ParamEnvAnd<'tcx, T> {
match self.reveal {
match self.reveal() {
Reveal::UserFacing => ParamEnvAnd { param_env: self, value },
Reveal::All => {

View file

@ -521,11 +521,8 @@ impl<'tcx, T: Lift<'tcx>> Lift<'tcx> for ty::Binder<T> {
impl<'a, 'tcx> Lift<'tcx> for ty::ParamEnv<'a> {
type Lifted = ty::ParamEnv<'tcx>;
fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
tcx.lift(&self.caller_bounds).map(|caller_bounds| ty::ParamEnv {
reveal: self.reveal,
caller_bounds,
def_id: self.def_id,
})
tcx.lift(&self.caller_bounds())
.map(|caller_bounds| ty::ParamEnv::new(caller_bounds, self.reveal(), self.def_id))
}
}

View file

@ -226,9 +226,9 @@ pub fn const_eval_validated_provider<'tcx>(
key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>,
) -> ::rustc_middle::mir::interpret::ConstEvalResult<'tcx> {
// see comment in const_eval_raw_provider for what we're doing here
if key.param_env.reveal == Reveal::All {
if key.param_env.reveal() == Reveal::All {
let mut key = key;
key.param_env.reveal = Reveal::UserFacing;
key.param_env = key.param_env.with_user_facing();
match tcx.const_eval_validated(key) {
// try again with reveal all as requested
Err(ErrorHandled::TooGeneric) => {}
@ -267,9 +267,9 @@ pub fn const_eval_raw_provider<'tcx>(
// information being available.
// In case we fail in the `UserFacing` variant, we just do the real computation.
if key.param_env.reveal == Reveal::All {
if key.param_env.reveal() == Reveal::All {
let mut key = key;
key.param_env.reveal = Reveal::UserFacing;
key.param_env = key.param_env.with_user_facing();
match tcx.const_eval_raw(key) {
// try again with reveal all as requested
Err(ErrorHandled::TooGeneric) => {}
@ -326,7 +326,7 @@ pub fn const_eval_raw_provider<'tcx>(
// this is `Reveal::UserFacing`, then it's expected that we could get a
// `TooGeneric` error. When we fall back to `Reveal::All`, then it will either
// succeed or we'll report this error then.
if key.param_env.reveal == Reveal::All {
if key.param_env.reveal() == Reveal::All {
tcx.sess.delay_span_bug(
err.span,
&format!("static eval failure did not emit an error: {:#?}", v),

View file

@ -279,7 +279,7 @@ where
let subpath = self.elaborator.field_subpath(variant_path, field);
let tcx = self.tcx();
assert_eq!(self.elaborator.param_env().reveal, Reveal::All);
assert_eq!(self.elaborator.param_env().reveal(), Reveal::All);
let field_ty =
tcx.normalize_erasing_regions(self.elaborator.param_env(), f.ty(tcx, substs));
(tcx.mk_place_field(base_place, field, field_ty), subpath)

View file

@ -281,8 +281,8 @@ impl AutoTraitFinder<'tcx> {
},
}));
let computed_preds = param_env.caller_bounds.iter();
let mut user_computed_preds: FxHashSet<_> = user_env.caller_bounds.iter().collect();
let computed_preds = param_env.caller_bounds().iter();
let mut user_computed_preds: FxHashSet<_> = user_env.caller_bounds().iter().collect();
let mut new_env = param_env;
let dummy_cause = ObligationCause::dummy();
@ -368,12 +368,12 @@ impl AutoTraitFinder<'tcx> {
)
.map(|o| o.predicate);
new_env =
ty::ParamEnv::new(tcx.mk_predicates(normalized_preds), param_env.reveal, None);
ty::ParamEnv::new(tcx.mk_predicates(normalized_preds), param_env.reveal(), None);
}
let final_user_env = ty::ParamEnv::new(
tcx.mk_predicates(user_computed_preds.into_iter()),
user_env.reveal,
user_env.reveal(),
None,
);
debug!(

View file

@ -137,7 +137,7 @@ fn in_environment(
let environment = match obligation.param_env.def_id {
Some(def_id) => environment(infcx.tcx, def_id),
None if obligation.param_env.caller_bounds.is_empty() => ty::List::empty(),
None if obligation.param_env.caller_bounds().is_empty() => ty::List::empty(),
// FIXME(chalk): this is hit in ui/where-clauses/where-clause-constraints-are-local-for-trait-impl
// and ui/generics/generic-static-methods
//_ => bug!("non-empty `ParamEnv` with no def-id"),

View file

@ -84,7 +84,7 @@ pub struct PendingPredicateObligation<'tcx> {
// `PendingPredicateObligation` is used a lot. Make sure it doesn't unintentionally get bigger.
#[cfg(target_arch = "x86_64")]
static_assert_size!(PendingPredicateObligation<'_>, 72);
static_assert_size!(PendingPredicateObligation<'_>, 64);
impl<'a, 'tcx> FulfillmentContext<'tcx> {
/// Creates a new fulfillment context.

View file

@ -297,7 +297,7 @@ pub fn normalize_param_env_or_error<'tcx>(
);
let mut predicates: Vec<_> =
util::elaborate_predicates(tcx, unnormalized_env.caller_bounds.into_iter())
util::elaborate_predicates(tcx, unnormalized_env.caller_bounds().into_iter())
.map(|obligation| obligation.predicate)
.collect();
@ -305,7 +305,7 @@ pub fn normalize_param_env_or_error<'tcx>(
let elaborated_env = ty::ParamEnv::new(
tcx.intern_predicates(&predicates),
unnormalized_env.reveal,
unnormalized_env.reveal(),
unnormalized_env.def_id,
);
@ -361,7 +361,7 @@ pub fn normalize_param_env_or_error<'tcx>(
let outlives_env: Vec<_> =
non_outlives_predicates.iter().chain(&outlives_predicates).cloned().collect();
let outlives_env =
ty::ParamEnv::new(tcx.intern_predicates(&outlives_env), unnormalized_env.reveal, None);
ty::ParamEnv::new(tcx.intern_predicates(&outlives_env), unnormalized_env.reveal(), None);
let outlives_predicates = match do_normalize_predicates(
tcx,
region_context,
@ -383,7 +383,7 @@ pub fn normalize_param_env_or_error<'tcx>(
debug!("normalize_param_env_or_error: final predicates={:?}", predicates);
ty::ParamEnv::new(
tcx.intern_predicates(&predicates),
unnormalized_env.reveal,
unnormalized_env.reveal(),
unnormalized_env.def_id,
)
}

View file

@ -631,7 +631,7 @@ fn receiver_is_dispatchable<'tcx>(
// create a modified param env, with `Self: Unsize<U>` and `U: Trait` added to caller bounds
// `U: ?Sized` is already implied here
let param_env = {
let mut param_env = tcx.param_env(method.def_id);
let param_env = tcx.param_env(method.def_id);
// Self: Unsize<U>
let unsize_predicate = ty::TraitRef {
@ -656,15 +656,17 @@ fn receiver_is_dispatchable<'tcx>(
};
let caller_bounds: Vec<Predicate<'tcx>> = param_env
.caller_bounds
.caller_bounds()
.iter()
.chain(iter::once(unsize_predicate))
.chain(iter::once(trait_predicate))
.collect();
param_env.caller_bounds = tcx.intern_predicates(&caller_bounds);
param_env
ty::ParamEnv::new(
tcx.intern_predicates(&caller_bounds),
param_env.reveal(),
param_env.def_id,
)
};
// Receiver: DispatchFromDyn<Receiver[Self => U]>

View file

@ -326,7 +326,7 @@ impl<'a, 'b, 'tcx> TypeFolder<'tcx> for AssocTypeNormalizer<'a, 'b, 'tcx> {
ty::Opaque(def_id, substs) if !substs.has_escaping_bound_vars() => {
// (*)
// Only normalize `impl Trait` after type-checking, usually in codegen.
match self.param_env.reveal {
match self.param_env.reveal() {
Reveal::UserFacing => ty,
Reveal::All => {
@ -869,7 +869,7 @@ fn assemble_candidates_from_param_env<'cx, 'tcx>(
obligation_trait_ref,
candidate_set,
ProjectionTyCandidate::ParamEnv,
obligation.param_env.caller_bounds.iter(),
obligation.param_env.caller_bounds().iter(),
);
}
@ -1028,7 +1028,7 @@ fn assemble_candidates_from_impls<'cx, 'tcx>(
// and the obligation is monomorphic, otherwise passes such as
// transmute checking and polymorphic MIR optimizations could
// get a result which isn't correct for all monomorphizations.
if obligation.param_env.reveal == Reveal::All {
if obligation.param_env.reveal() == Reveal::All {
// NOTE(eddyb) inference variables can resolve to parameters, so
// assume `poly_trait_ref` isn't monomorphic, if it contains any.
let poly_trait_ref =

View file

@ -104,7 +104,7 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> {
ty::Opaque(def_id, substs) if !substs.has_escaping_bound_vars() => {
// (*)
// Only normalize `impl Trait` after type-checking, usually in codegen.
match self.param_env.reveal {
match self.param_env.reveal() {
Reveal::UserFacing => ty,
Reveal::All => {

View file

@ -186,7 +186,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
let all_bounds = stack
.obligation
.param_env
.caller_bounds
.caller_bounds()
.iter()
.filter_map(|o| o.to_opt_poly_trait_ref());

View file

@ -552,7 +552,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
if !self.intercrate
&& obligation.is_global()
&& obligation.param_env.caller_bounds.iter().all(|bound| bound.needs_subst())
&& obligation.param_env.caller_bounds().iter().all(|bound| bound.needs_subst())
{
// If a param env has no global bounds, global obligations do not
// depend on its particular value in order to work, so we can clear

View file

@ -231,7 +231,10 @@ fn fulfill_implication<'a, 'tcx>(
debug!(
"fulfill_implication: for impls on {:?} and {:?}, \
could not fulfill: {:?} given {:?}",
source_trait_ref, target_trait_ref, errors, param_env.caller_bounds
source_trait_ref,
target_trait_ref,
errors,
param_env.caller_bounds()
);
Err(())
}

View file

@ -126,7 +126,7 @@ fn resolve_associated_item<'tcx>(
// and the obligation is monomorphic, otherwise passes such as
// transmute checking and polymorphic MIR optimizations could
// get a result which isn't correct for all monomorphizations.
if param_env.reveal == Reveal::All {
if param_env.reveal() == Reveal::All {
!trait_ref.still_further_specializable()
} else {
false

View file

@ -218,7 +218,7 @@ fn compare_predicate_entailment<'tcx>(
let inh = Inherited::new(infcx, impl_m.def_id.expect_local());
let infcx = &inh.infcx;
debug!("compare_impl_method: caller_bounds={:?}", param_env.caller_bounds);
debug!("compare_impl_method: caller_bounds={:?}", param_env.caller_bounds());
let mut selcx = traits::SelectionContext::new(&infcx);
@ -1141,7 +1141,7 @@ fn compare_type_predicate_entailment<'tcx>(
let inh = Inherited::new(infcx, impl_ty.def_id.expect_local());
let infcx = &inh.infcx;
debug!("compare_type_predicate_entailment: caller_bounds={:?}", param_env.caller_bounds);
debug!("compare_type_predicate_entailment: caller_bounds={:?}", param_env.caller_bounds());
let mut selcx = traits::SelectionContext::new(&infcx);

View file

@ -798,26 +798,25 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
// FIXME: do we want to commit to this behavior for param bounds?
debug!("assemble_inherent_candidates_from_param(param_ty={:?})", param_ty);
let bounds =
self.param_env.caller_bounds.iter().filter_map(|predicate| match predicate.kind() {
ty::PredicateKind::Trait(ref trait_predicate, _) => {
match trait_predicate.skip_binder().trait_ref.self_ty().kind {
ty::Param(ref p) if *p == param_ty => {
Some(trait_predicate.to_poly_trait_ref())
}
_ => None,
}
let bounds = self.param_env.caller_bounds().iter().filter_map(|predicate| match predicate
.kind()
{
ty::PredicateKind::Trait(ref trait_predicate, _) => {
match trait_predicate.skip_binder().trait_ref.self_ty().kind {
ty::Param(ref p) if *p == param_ty => Some(trait_predicate.to_poly_trait_ref()),
_ => None,
}
ty::PredicateKind::Subtype(..)
| ty::PredicateKind::Projection(..)
| ty::PredicateKind::RegionOutlives(..)
| ty::PredicateKind::WellFormed(..)
| ty::PredicateKind::ObjectSafe(..)
| ty::PredicateKind::ClosureKind(..)
| ty::PredicateKind::TypeOutlives(..)
| ty::PredicateKind::ConstEvaluatable(..)
| ty::PredicateKind::ConstEquate(..) => None,
});
}
ty::PredicateKind::Subtype(..)
| ty::PredicateKind::Projection(..)
| ty::PredicateKind::RegionOutlives(..)
| ty::PredicateKind::WellFormed(..)
| ty::PredicateKind::ObjectSafe(..)
| ty::PredicateKind::ClosureKind(..)
| ty::PredicateKind::TypeOutlives(..)
| ty::PredicateKind::ConstEvaluatable(..)
| ty::PredicateKind::ConstEquate(..) => None,
});
self.elaborate_bounds(bounds, |this, poly_trait_ref, item| {
let trait_ref = this.erase_late_bound_regions(&poly_trait_ref);

View file

@ -2927,18 +2927,20 @@ impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> {
let index = generics.param_def_id_to_index[&def_id];
ty::GenericPredicates {
parent: None,
predicates: tcx.arena.alloc_from_iter(self.param_env.caller_bounds.iter().filter_map(
|predicate| match predicate.kind() {
ty::PredicateKind::Trait(ref data, _)
if data.skip_binder().self_ty().is_param(index) =>
{
// HACK(eddyb) should get the original `Span`.
let span = tcx.def_span(def_id);
Some((predicate, span))
predicates: tcx.arena.alloc_from_iter(
self.param_env.caller_bounds().iter().filter_map(|predicate| {
match predicate.kind() {
ty::PredicateKind::Trait(ref data, _)
if data.skip_binder().self_ty().is_param(index) =>
{
// HACK(eddyb) should get the original `Span`.
let span = tcx.def_span(def_id);
Some((predicate, span))
}
_ => None,
}
_ => None,
},
)),
}),
),
}
}

View file

@ -459,9 +459,9 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> {
let mut replacer = RegionReplacer { vid_to_region: &vid_to_region, tcx };
let orig_bounds: FxHashSet<_> =
self.cx.tcx.param_env(param_env_def_id).caller_bounds.iter().collect();
self.cx.tcx.param_env(param_env_def_id).caller_bounds().iter().collect();
let clean_where_predicates = param_env
.caller_bounds
.caller_bounds()
.iter()
.filter(|p| {
!orig_bounds.contains(p)

View file

@ -111,7 +111,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NeedlessPassByValue {
let fn_def_id = cx.tcx.hir().local_def_id(hir_id);
let preds = traits::elaborate_predicates(cx.tcx, cx.param_env.caller_bounds.iter())
let preds = traits::elaborate_predicates(cx.tcx, cx.param_env.caller_bounds().iter())
.filter(|p| !p.is_global())
.filter_map(|obligation| {
if let ty::PredicateKind::Trait(poly_trait_ref, _) = obligation.predicate.kind() {