From 0fd8cb45b4f19b433aea080c5e0f296954db8ded Mon Sep 17 00:00:00 2001 From: Havvy Date: Wed, 30 May 2018 00:37:32 -0700 Subject: [PATCH 1/3] Update outdated comment for split_auto_traits private fn --- src/librustc_typeck/astconv.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 68587fb8b3c1e..bce331862e1f4 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -1318,7 +1318,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { } } -/// Divides a list of general trait bounds into two groups: builtin bounds (Sync/Send) and the +/// Divides a list of general trait bounds into two groups: auto traits (e.g. Sync and Send) and the /// remaining general trait bounds. fn split_auto_traits<'a, 'b, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, trait_bounds: &'b [hir::PolyTraitRef]) From 86ff9fa9c95b618605fad27bd752486c6259187b Mon Sep 17 00:00:00 2001 From: Havvy Date: Fri, 1 Jun 2018 08:52:07 -0700 Subject: [PATCH 2/3] 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 bce331862e1f4..68553ece3a750 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 0000000000000..9f5845f6d77b0 --- /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 0000000000000..d3e4627a4c9b8 --- /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 0000000000000..9abd81cdcfa23 --- /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`. From eccd2ede3c1b11ddcdde7929e049c4773df690ae Mon Sep 17 00:00:00 2001 From: Havvy Date: Wed, 6 Jun 2018 22:11:37 -0700 Subject: [PATCH 3/3] Use Ord::cmp for auto traits since stable sort not needed --- src/librustc_typeck/astconv.rs | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 68553ece3a750..da98dc5d14b46 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -30,7 +30,7 @@ use util::common::ErrorReported; use util::nodemap::{FxHashSet, FxHashMap}; use errors::FatalError; -use std::cmp::Ordering; +// use std::cmp::Ordering; use std::iter; use syntax::ast; use syntax::feature_gate::{GateIssue, emit_feature_err}; @@ -646,7 +646,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { &mut vec![]); } - let (auto_traits, trait_bounds) = split_auto_traits(tcx, &trait_bounds[1..]); + let (mut auto_traits, trait_bounds) = split_auto_traits(tcx, &trait_bounds[1..]); if !trait_bounds.is_empty() { let b = &trait_bounds[0]; @@ -708,15 +708,13 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { } // 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); + auto_traits.sort(); + auto_traits.dedup(); // 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()) + .chain(auto_traits.into_iter().map(ty::ExistentialPredicate::AutoTrait)) .chain(existential_projections .map(|x| ty::ExistentialPredicate::Projection(*x.skip_binder()))) .collect::>();