Skip to content

Commit 86ff9fa

Browse files
committed
Dedup auto traits in trait objects
1 parent 0fd8cb4 commit 86ff9fa

File tree

4 files changed

+102
-1
lines changed

4 files changed

+102
-1
lines changed

src/librustc_typeck/astconv.rs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ use util::common::ErrorReported;
3030
use util::nodemap::{FxHashSet, FxHashMap};
3131
use errors::FatalError;
3232

33+
use std::cmp::Ordering;
3334
use std::iter;
3435
use syntax::ast;
3536
use syntax::feature_gate::{GateIssue, emit_feature_err};
@@ -706,10 +707,16 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
706707
.emit();
707708
}
708709

710+
// Dedup auto traits so that `dyn Trait + Send + Send` is the same as `dyn Trait + Send`.
711+
let mut auto_traits =
712+
auto_traits.into_iter().map(ty::ExistentialPredicate::AutoTrait).collect::<Vec<_>>();
713+
auto_traits.sort_by(|a, b| a.cmp(tcx, b));
714+
auto_traits.dedup_by(|a, b| (&*a).cmp(tcx, b) == Ordering::Equal);
715+
709716
// skip_binder is okay, because the predicates are re-bound.
710717
let mut v =
711718
iter::once(ty::ExistentialPredicate::Trait(*existential_principal.skip_binder()))
712-
.chain(auto_traits.into_iter().map(ty::ExistentialPredicate::AutoTrait))
719+
.chain(auto_traits.into_iter())
713720
.chain(existential_projections
714721
.map(|x| ty::ExistentialPredicate::Projection(*x.skip_binder())))
715722
.collect::<AccumulateVec<[_; 8]>>();
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
// Copyright 2014 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+
// Test that duplicate auto trait bounds in trait objects don't create new types.
12+
#[allow(unused_assignments)]
13+
14+
use std::marker::Send as SendAlias;
15+
16+
// A dummy trait for the non-auto trait.
17+
trait Trait {}
18+
19+
// A dummy struct to implement Trait, Send, and .
20+
struct Struct;
21+
22+
impl Trait for Struct {}
23+
24+
// These three functions should be equivalent.
25+
fn takes_dyn_trait_send(_: Box<dyn Trait + Send>) {}
26+
fn takes_dyn_trait_send_send(_: Box<dyn Trait + Send + Send>) {}
27+
fn takes_dyn_trait_send_sendalias(_: Box<dyn Trait + Send + SendAlias>) {}
28+
29+
impl dyn Trait + Send + Send {
30+
fn do_nothing(&self) {}
31+
}
32+
33+
fn main() {
34+
// 1. Moving into a variable with more Sends and back.
35+
let mut dyn_trait_send = Box::new(Struct) as Box<dyn Trait + Send>;
36+
let dyn_trait_send_send: Box<dyn Trait + Send + Send> = dyn_trait_send;
37+
dyn_trait_send = dyn_trait_send_send;
38+
39+
// 2. Calling methods with different number of Sends.
40+
let dyn_trait_send = Box::new(Struct) as Box<dyn Trait + Send>;
41+
takes_dyn_trait_send_send(dyn_trait_send);
42+
43+
let dyn_trait_send_send = Box::new(Struct) as Box<dyn Trait + Send + Send>;
44+
takes_dyn_trait_send(dyn_trait_send_send);
45+
46+
// 3. Aliases to the trait are transparent.
47+
let dyn_trait_send = Box::new(Struct) as Box<dyn Trait + Send>;
48+
takes_dyn_trait_send_sendalias(dyn_trait_send);
49+
50+
// 4. Calling an impl that duplicates an auto trait.
51+
let dyn_trait_send = Box::new(Struct) as Box<dyn Trait + Send>;
52+
dyn_trait_send.do_nothing();
53+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
// Copyright 2014 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+
// Checks to make sure that `dyn Trait + Send` and `dyn Trait + Send + Send` are the same type.
12+
// Issue: #47010
13+
14+
struct Struct;
15+
impl Trait for Struct {}
16+
trait Trait {}
17+
18+
type Send1 = Trait + Send;
19+
type Send2 = Trait + Send + Send;
20+
21+
fn main () {}
22+
23+
impl Trait + Send {
24+
fn test(&self) { println!("one"); } //~ ERROR duplicate definitions with name `test`
25+
}
26+
27+
impl Trait + Send + Send {
28+
fn test(&self) { println!("two"); }
29+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
error[E0592]: duplicate definitions with name `test`
2+
--> $DIR/trait-object-auto-dedup-in-impl.rs:24:5
3+
|
4+
LL | fn test(&self) { println!("one"); } //~ ERROR duplicate definitions with name `test`
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ duplicate definitions for `test`
6+
...
7+
LL | fn test(&self) { println!("two"); }
8+
| ----------------------------------- other definition for `test`
9+
10+
error: aborting due to previous error
11+
12+
For more information about this error, try `rustc --explain E0592`.

0 commit comments

Comments
 (0)