From 86ff9fa9c95b618605fad27bd752486c6259187b Mon Sep 17 00:00:00 2001 From: Havvy Date: Fri, 1 Jun 2018 08:52:07 -0700 Subject: [PATCH] Dedup auto traits in trait objects --- src/librustc_typeck/astconv.rs | 9 +++- src/test/run-pass/trait-object-auto-dedup.rs | 53 +++++++++++++++++++ .../ui/trait-object-auto-dedup-in-impl.rs | 29 ++++++++++ .../ui/trait-object-auto-dedup-in-impl.stderr | 12 +++++ 4 files changed, 102 insertions(+), 1 deletion(-) create mode 100644 src/test/run-pass/trait-object-auto-dedup.rs create mode 100644 src/test/ui/trait-object-auto-dedup-in-impl.rs create mode 100644 src/test/ui/trait-object-auto-dedup-in-impl.stderr diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index bce331862e1..68553ece3a7 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -30,6 +30,7 @@ use util::common::ErrorReported; use util::nodemap::{FxHashSet, FxHashMap}; use errors::FatalError; +use std::cmp::Ordering; use std::iter; use syntax::ast; use syntax::feature_gate::{GateIssue, emit_feature_err}; @@ -706,10 +707,16 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { .emit(); } + // Dedup auto traits so that `dyn Trait + Send + Send` is the same as `dyn Trait + Send`. + let mut auto_traits = + auto_traits.into_iter().map(ty::ExistentialPredicate::AutoTrait).collect::>(); + auto_traits.sort_by(|a, b| a.cmp(tcx, b)); + auto_traits.dedup_by(|a, b| (&*a).cmp(tcx, b) == Ordering::Equal); + // skip_binder is okay, because the predicates are re-bound. let mut v = iter::once(ty::ExistentialPredicate::Trait(*existential_principal.skip_binder())) - .chain(auto_traits.into_iter().map(ty::ExistentialPredicate::AutoTrait)) + .chain(auto_traits.into_iter()) .chain(existential_projections .map(|x| ty::ExistentialPredicate::Projection(*x.skip_binder()))) .collect::>(); diff --git a/src/test/run-pass/trait-object-auto-dedup.rs b/src/test/run-pass/trait-object-auto-dedup.rs new file mode 100644 index 00000000000..9f5845f6d77 --- /dev/null +++ b/src/test/run-pass/trait-object-auto-dedup.rs @@ -0,0 +1,53 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Test that duplicate auto trait bounds in trait objects don't create new types. +#[allow(unused_assignments)] + +use std::marker::Send as SendAlias; + +// A dummy trait for the non-auto trait. +trait Trait {} + +// A dummy struct to implement Trait, Send, and . +struct Struct; + +impl Trait for Struct {} + +// These three functions should be equivalent. +fn takes_dyn_trait_send(_: Box) {} +fn takes_dyn_trait_send_send(_: Box) {} +fn takes_dyn_trait_send_sendalias(_: Box) {} + +impl dyn Trait + Send + Send { + fn do_nothing(&self) {} +} + +fn main() { + // 1. Moving into a variable with more Sends and back. + let mut dyn_trait_send = Box::new(Struct) as Box; + let dyn_trait_send_send: Box = dyn_trait_send; + dyn_trait_send = dyn_trait_send_send; + + // 2. Calling methods with different number of Sends. + let dyn_trait_send = Box::new(Struct) as Box; + takes_dyn_trait_send_send(dyn_trait_send); + + let dyn_trait_send_send = Box::new(Struct) as Box; + takes_dyn_trait_send(dyn_trait_send_send); + + // 3. Aliases to the trait are transparent. + let dyn_trait_send = Box::new(Struct) as Box; + takes_dyn_trait_send_sendalias(dyn_trait_send); + + // 4. Calling an impl that duplicates an auto trait. + let dyn_trait_send = Box::new(Struct) as Box; + dyn_trait_send.do_nothing(); +} diff --git a/src/test/ui/trait-object-auto-dedup-in-impl.rs b/src/test/ui/trait-object-auto-dedup-in-impl.rs new file mode 100644 index 00000000000..d3e4627a4c9 --- /dev/null +++ b/src/test/ui/trait-object-auto-dedup-in-impl.rs @@ -0,0 +1,29 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Checks to make sure that `dyn Trait + Send` and `dyn Trait + Send + Send` are the same type. +// Issue: #47010 + +struct Struct; +impl Trait for Struct {} +trait Trait {} + +type Send1 = Trait + Send; +type Send2 = Trait + Send + Send; + +fn main () {} + +impl Trait + Send { + fn test(&self) { println!("one"); } //~ ERROR duplicate definitions with name `test` +} + +impl Trait + Send + Send { + fn test(&self) { println!("two"); } +} diff --git a/src/test/ui/trait-object-auto-dedup-in-impl.stderr b/src/test/ui/trait-object-auto-dedup-in-impl.stderr new file mode 100644 index 00000000000..9abd81cdcfa --- /dev/null +++ b/src/test/ui/trait-object-auto-dedup-in-impl.stderr @@ -0,0 +1,12 @@ +error[E0592]: duplicate definitions with name `test` + --> $DIR/trait-object-auto-dedup-in-impl.rs:24:5 + | +LL | fn test(&self) { println!("one"); } //~ ERROR duplicate definitions with name `test` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ duplicate definitions for `test` +... +LL | fn test(&self) { println!("two"); } + | ----------------------------------- other definition for `test` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0592`.