Skip to content

Commit a0943b6

Browse files
committed
Filter out duplicated trait predicates when generating auto traits
Fixes #51236
1 parent bff08f2 commit a0943b6

File tree

2 files changed

+87
-3
lines changed

2 files changed

+87
-3
lines changed

src/librustc/traits/auto_trait.rs

+63-3
Original file line numberDiff line numberDiff line change
@@ -326,6 +326,9 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> {
326326
let mut user_computed_preds: FxHashSet<_> =
327327
user_env.caller_bounds.iter().cloned().collect();
328328

329+
330+
331+
329332
let mut new_env = param_env.clone();
330333
let dummy_cause = ObligationCause::misc(DUMMY_SP, ast::DUMMY_NODE_ID);
331334

@@ -358,7 +361,8 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> {
358361
&Err(SelectionError::Unimplemented) => {
359362
if self.is_of_param(pred.skip_binder().trait_ref.substs) {
360363
already_visited.remove(&pred);
361-
user_computed_preds.insert(ty::Predicate::Trait(pred.clone()));
364+
self.add_user_pred(&mut user_computed_preds, ty::Predicate::Trait(pred.clone()));
365+
//user_computed_preds.insert(ty::Predicate::Trait(pred.clone()));
362366
predicates.push_back(pred);
363367
} else {
364368
debug!(
@@ -393,6 +397,62 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> {
393397
return Some((new_env, final_user_env));
394398
}
395399

400+
fn add_user_pred<'c>(&self, user_computed_preds: &mut FxHashSet<ty::Predicate<'c>>, new_pred: ty::Predicate<'c>) {
401+
let mut should_add_new = true;
402+
user_computed_preds.retain(|&old_pred| {
403+
match (&new_pred, old_pred) {
404+
(&ty::Predicate::Trait(new_trait), ty::Predicate::Trait(old_trait)) => {
405+
if new_trait.def_id() == old_trait.def_id() {
406+
let new_substs = new_trait.skip_binder().trait_ref.substs;
407+
let old_substs = old_trait.skip_binder().trait_ref.substs;
408+
if !new_substs.types().eq(old_substs.types()) {
409+
// We can't compare lifetimes if the types are different,
410+
// so skip checking old_pred
411+
return true
412+
}
413+
414+
for (new_region, old_region) in new_substs.regions().zip(old_substs.regions()) {
415+
match (new_region, old_region) {
416+
// If both predicates have an 'ReLateBound' (a HRTB) in the
417+
// same spot, we do nothing
418+
(ty::RegionKind::ReLateBound(_, _), ty::RegionKind::ReLateBound(_, _)) => {},
419+
420+
(ty::RegionKind::ReLateBound(_, _), _) => {
421+
// The new predicate has a HRTB in a spot where the old
422+
// predicate does not (if they both had a HRTB, the previous
423+
// match arm would have executed).
424+
//
425+
// The means we want to remove the older predicate from
426+
// user_computed_preds, since having both it and the new
427+
// predicate in a ParamEnv would confuse SelectionContext
428+
// We're currently in the predicate passed to 'retain',
429+
// so we return 'false' to remove the old predicate from
430+
// user_computed_preds
431+
return false;
432+
},
433+
(_, ty::RegionKind::ReLateBound(_, _)) => {
434+
// This is the opposite situation as the previous arm - the
435+
// old predicate has a HRTB lifetime in a place where the
436+
// new predicate does not. We want to leave the old
437+
// predicate in user_computed_preds, and skip adding
438+
// new_pred to user_computed_params.
439+
should_add_new = false
440+
}
441+
_ => {}
442+
}
443+
}
444+
}
445+
},
446+
_ => {}
447+
}
448+
return true
449+
});
450+
451+
if should_add_new {
452+
user_computed_preds.insert(new_pred);
453+
}
454+
}
455+
396456
pub fn region_name(&self, region: Region) -> Option<String> {
397457
match region {
398458
&ty::ReEarlyBound(r) => Some(r.name.to_string()),
@@ -555,15 +615,15 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> {
555615
let substs = &p.skip_binder().trait_ref.substs;
556616

557617
if self.is_of_param(substs) && !only_projections && is_new_pred {
558-
computed_preds.insert(predicate);
618+
self.add_user_pred(computed_preds, predicate);
559619
}
560620
predicates.push_back(p.clone());
561621
}
562622
&ty::Predicate::Projection(p) => {
563623
// If the projection isn't all type vars, then
564624
// we don't want to add it as a bound
565625
if self.is_of_param(p.skip_binder().projection_ty.substs) && is_new_pred {
566-
computed_preds.insert(predicate);
626+
self.add_user_pred(computed_preds, predicate);
567627
} else {
568628
match poly_project_and_unify_type(select, &obligation.with(p.clone())) {
569629
Err(e) => {

src/test/rustdoc/issue-51236.rs

+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
use std::marker::PhantomData;
12+
13+
pub mod traits {
14+
pub trait Owned<'a> {
15+
type Reader;
16+
}
17+
}
18+
19+
// @has issue_51236/struct.Owned.html
20+
// @has - '//*[@id="synthetic-implementations-list"]/*[@class="impl"]//*/code' "impl<T> Send for \
21+
// Owned<T> where <T as Owned<'static>>::Reader: Send"
22+
pub struct Owned<T> where T: for<'a> ::traits::Owned<'a> {
23+
marker: PhantomData<<T as ::traits::Owned<'static>>::Reader>,
24+
}

0 commit comments

Comments
 (0)