Skip to content

Commit

Permalink
Auto merge of rust-lang#75595 - davidtwco:polymorphization-predicate-…
Browse files Browse the repository at this point in the history
…simplification-correction, r=eddyb

polymorphize: if any param in a predicate is used, then all are used

Addresses [review](rust-lang#75518 (comment)) [comments](rust-lang#75518 (comment)) [from](rust-lang#75518 (comment)) @eddyb in rust-lang#75518 that I didn't get to resolve before bors merged.

This PR modifies polymorphization's handling of predicates so that if any generic parameter is used in a predicate then all parameters in that predicate are used.

r? @eddyb
  • Loading branch information
bors committed Aug 20, 2020
2 parents f6049b6 + 5703b28 commit 1a22a0f
Show file tree
Hide file tree
Showing 2 changed files with 29 additions and 75 deletions.
87 changes: 12 additions & 75 deletions src/librustc_mir/monomorphize/polymorphize.rs
Expand Up @@ -119,16 +119,6 @@ fn mark_used_by_predicates<'tcx>(
def_id: DefId,
unused_parameters: &mut FiniteBitSet<u32>,
) {
let is_ty_used = |unused_parameters: &FiniteBitSet<u32>, ty: Ty<'tcx>| -> bool {
let mut vis = IsUsedGenericParams { unused_parameters };
ty.visit_with(&mut vis)
};

let mark_ty = |unused_parameters: &mut FiniteBitSet<u32>, ty: Ty<'tcx>| {
let mut vis = MarkUsedGenericParams { tcx, def_id, unused_parameters };
ty.visit_with(&mut vis);
};

let def_id = tcx.closure_base_def_id(def_id);
let predicates = tcx.explicit_predicates_of(def_id);
debug!("mark_used_by_predicates: predicates_of={:?}", predicates);
Expand All @@ -144,69 +134,16 @@ fn mark_used_by_predicates<'tcx>(
current_unused_parameters = *unused_parameters;

for (predicate, _) in predicates.predicates {
match predicate.skip_binders() {
ty::PredicateAtom::Trait(predicate, ..) => {
let trait_ref = predicate.trait_ref;
debug!("mark_used_by_predicates: (trait) trait_ref={:?}", trait_ref);

// Consider `T` used if `I` is used in predicates of the form
// `I: Iterator<Item = T>`
debug!("mark_used_by_predicates: checking self");
if is_ty_used(unused_parameters, trait_ref.self_ty()) {
debug!("mark_used_by_predicates: used!");
for ty in trait_ref.substs.types() {
mark_ty(unused_parameters, ty);
}

// No need to check for a type being used in the substs if `self_ty` was
// used.
continue;
}

// Consider `I` used if `T` is used in predicates of the form
// `I: Iterator<Item = &'a (T, E)>` (see rust-lang/rust#75326)
debug!("mark_used_by_predicates: checking substs");
for ty in trait_ref.substs.types() {
if is_ty_used(unused_parameters, ty) {
debug!("mark_used_by_predicates: used!");
mark_ty(unused_parameters, trait_ref.self_ty());
}
}
}
ty::PredicateAtom::Projection(proj, ..) => {
let self_ty = proj.projection_ty.self_ty();
debug!(
"mark_used_by_predicates: (projection) self_ty={:?} proj.ty={:?}",
self_ty, proj.ty
);

// Consider `T` used if `I` is used in predicates of the form
// `<I as Iterator>::Item = T`
debug!("mark_used_by_predicates: checking self");
if is_ty_used(unused_parameters, self_ty) {
debug!("mark_used_by_predicates: used!");
mark_ty(unused_parameters, proj.ty);

// No need to check for projection type being used if `self_ty` was used.
continue;
}

// Consider `I` used if `T` is used in predicates of the form
// `<I as Iterator>::Item = &'a (T, E)` (see rust-lang/rust#75326)
debug!("mark_used_by_predicates: checking projection ty");
if is_ty_used(unused_parameters, proj.ty) {
debug!("mark_used_by_predicates: used!");
mark_ty(unused_parameters, self_ty);
}
}
ty::PredicateAtom::RegionOutlives(..)
| ty::PredicateAtom::TypeOutlives(..)
| ty::PredicateAtom::WellFormed(..)
| ty::PredicateAtom::ObjectSafe(..)
| ty::PredicateAtom::ClosureKind(..)
| ty::PredicateAtom::Subtype(..)
| ty::PredicateAtom::ConstEvaluatable(..)
| ty::PredicateAtom::ConstEquate(..) => (),
// Consider all generic params in a predicate as used if any other parameter in the
// predicate is used.
let any_param_used = {
let mut vis = HasUsedGenericParams { unused_parameters };
predicate.visit_with(&mut vis)
};

if any_param_used {
let mut vis = MarkUsedGenericParams { tcx, def_id, unused_parameters };
predicate.visit_with(&mut vis);
}
}
}
Expand Down Expand Up @@ -375,11 +312,11 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for MarkUsedGenericParams<'a, 'tcx> {
}

/// Visitor used to check if a generic parameter is used.
struct IsUsedGenericParams<'a> {
struct HasUsedGenericParams<'a> {
unused_parameters: &'a FiniteBitSet<u32>,
}

impl<'a, 'tcx> TypeVisitor<'tcx> for IsUsedGenericParams<'a> {
impl<'a, 'tcx> TypeVisitor<'tcx> for HasUsedGenericParams<'a> {
fn visit_const(&mut self, c: &'tcx Const<'tcx>) -> bool {
debug!("visit_const: c={:?}", c);
if !c.has_param_types_or_consts() {
Expand Down
17 changes: 17 additions & 0 deletions src/test/ui/polymorphization/predicates.rs
Expand Up @@ -60,6 +60,21 @@ where
std::mem::size_of::<C>()
}

// Finally, check that `F` is considered used because `G` is used when neither are in the self-ty
// of the predicate.

trait Foobar<F, G> {}

impl Foobar<u32, u32> for () {}

#[rustc_polymorphize_error]
fn foobar<F, G>() -> usize
where
(): Foobar<F, G>,
{
std::mem::size_of::<G>()
}

fn main() {
let x = &[2u32];
foo(x.iter());
Expand All @@ -69,4 +84,6 @@ fn main() {
let _ = a.next();

let _ = quux::<u8, u16, u32>();

let _ = foobar::<u32, u32>();
}

0 comments on commit 1a22a0f

Please sign in to comment.