diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index 38ea1e4a19b91..b54b9edc78dde 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -1724,7 +1724,8 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { if other.evaluation == EvaluatedToOk { if let ImplCandidate(victim_def) = victim.candidate { let tcx = self.tcx().global_tcx(); - return traits::specializes(tcx, other_def, victim_def); + return traits::specializes(tcx, other_def, victim_def) || + tcx.impls_are_allowed_to_overlap(other_def, victim_def); } } diff --git a/src/librustc/traits/specialize/specialization_graph.rs b/src/librustc/traits/specialize/specialization_graph.rs index 40eb69395678f..6e2c16c82aeb4 100644 --- a/src/librustc/traits/specialize/specialization_graph.rs +++ b/src/librustc/traits/specialize/specialization_graph.rs @@ -113,6 +113,10 @@ impl<'a, 'gcx, 'tcx> Children { possible_sibling, impl_def_id); if let Some(impl_header) = overlap { + if tcx.impls_are_allowed_to_overlap(impl_def_id, possible_sibling) { + return Ok((false, false)); + } + let le = specializes(tcx, impl_def_id, possible_sibling); let ge = specializes(tcx, possible_sibling, impl_def_id); diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 6a4e7db21dd12..e9f35a5808b7d 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -2158,6 +2158,25 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { queries::impl_trait_ref::get(self, DUMMY_SP, id) } + /// Returns true if the impls are the same polarity and are implementing + /// a trait which contains no items + pub fn impls_are_allowed_to_overlap(self, def_id1: DefId, def_id2: DefId) -> bool { + if !self.sess.features.borrow().overlapping_marker_traits { + return false; + } + let trait1_is_empty = self.impl_trait_ref(def_id1) + .map_or(false, |trait_ref| { + self.associated_item_def_ids(trait_ref.def_id).is_empty() + }); + let trait2_is_empty = self.impl_trait_ref(def_id2) + .map_or(false, |trait_ref| { + self.associated_item_def_ids(trait_ref.def_id).is_empty() + }); + self.trait_impl_polarity(def_id1) == self.trait_impl_polarity(def_id2) + && trait1_is_empty + && trait2_is_empty + } + // Returns `ty::VariantDef` if `def` refers to a struct, // or variant or their constructors, panics otherwise. pub fn expect_variant_def(self, def: Def) -> &'tcx VariantDef { diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 12d25ca4274fe..690cf03513c89 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -342,6 +342,9 @@ declare_features! ( // See rust-lang/rfcs#1414. Allows code like `let x: &'static u32 = &42` to work. (active, rvalue_static_promotion, "1.15.1", Some(38865)), + + // Allows overlapping impls of marker traits + (active, overlapping_marker_traits, "1.18.0", Some(29864)), ); declare_features! ( diff --git a/src/test/compile-fail/E0120.rs b/src/test/compile-fail/E0120.rs index 3fdeb75317540..80cc0d2680f7c 100644 --- a/src/test/compile-fail/E0120.rs +++ b/src/test/compile-fail/E0120.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -trait MyTrait {} +trait MyTrait { fn foo() {} } impl Drop for MyTrait { //~^ ERROR E0120 diff --git a/src/test/compile-fail/auxiliary/trait_impl_conflict.rs b/src/test/compile-fail/auxiliary/trait_impl_conflict.rs index c3ecbb014dc6b..3190ce430ad67 100644 --- a/src/test/compile-fail/auxiliary/trait_impl_conflict.rs +++ b/src/test/compile-fail/auxiliary/trait_impl_conflict.rs @@ -9,6 +9,7 @@ // except according to those terms. pub trait Foo { + fn foo() {} } impl Foo for isize { diff --git a/src/test/compile-fail/coherence-conflicting-negative-trait-impl.rs b/src/test/compile-fail/coherence-conflicting-negative-trait-impl.rs index 7fd1b17f2966c..8e9d1eff34580 100644 --- a/src/test/compile-fail/coherence-conflicting-negative-trait-impl.rs +++ b/src/test/compile-fail/coherence-conflicting-negative-trait-impl.rs @@ -9,6 +9,7 @@ // except according to those terms. #![feature(optin_builtin_traits)] +#![feature(overlapping_marker_traits)] trait MyTrait {} @@ -20,8 +21,8 @@ impl !Send for TestType {} //~^ ERROR conflicting implementations of trait `std::marker::Send` unsafe impl Send for TestType {} -//~^ ERROR conflicting implementations of trait `std::marker::Send` impl !Send for TestType {} +//~^ ERROR conflicting implementations of trait `std::marker::Send` fn main() {} diff --git a/src/test/compile-fail/coherence-default-trait-impl.rs b/src/test/compile-fail/coherence-default-trait-impl.rs index 15a80c64f8b06..e6bf068156c2b 100644 --- a/src/test/compile-fail/coherence-default-trait-impl.rs +++ b/src/test/compile-fail/coherence-default-trait-impl.rs @@ -10,7 +10,7 @@ #![feature(optin_builtin_traits)] -trait MyTrait {} +trait MyTrait { fn foo() {} } impl MyTrait for .. {} //~^ ERROR redundant default implementations of trait `MyTrait` diff --git a/src/test/compile-fail/coherence-impls-send.rs b/src/test/compile-fail/coherence-impls-send.rs index f130a9353516f..9caaee41aeb1d 100644 --- a/src/test/compile-fail/coherence-impls-send.rs +++ b/src/test/compile-fail/coherence-impls-send.rs @@ -9,6 +9,7 @@ // except according to those terms. #![feature(optin_builtin_traits)] +#![feature(overlapping_marker_traits)] use std::marker::Copy; @@ -34,7 +35,6 @@ unsafe impl Send for [MyType] {} unsafe impl Send for &'static [NotSync] {} //~^ ERROR E0117 -//~| ERROR E0119 fn main() { } diff --git a/src/test/compile-fail/coherence-no-direct-lifetime-dispatch.rs b/src/test/compile-fail/coherence-no-direct-lifetime-dispatch.rs index 6de338f1db0fa..47026cd32d411 100644 --- a/src/test/compile-fail/coherence-no-direct-lifetime-dispatch.rs +++ b/src/test/compile-fail/coherence-no-direct-lifetime-dispatch.rs @@ -10,7 +10,7 @@ // Test that you cannot *directly* dispatch on lifetime requirements -trait MyTrait {} +trait MyTrait { fn foo() {} } impl MyTrait for T {} impl MyTrait for T {} //~ ERROR E0119 diff --git a/src/test/compile-fail/coherence-overlap-all-t-and-tuple.rs b/src/test/compile-fail/coherence-overlap-all-t-and-tuple.rs index 928ba7a36db26..1fad608db6c3b 100644 --- a/src/test/compile-fail/coherence-overlap-all-t-and-tuple.rs +++ b/src/test/compile-fail/coherence-overlap-all-t-and-tuple.rs @@ -17,6 +17,7 @@ // Seems pretty basic, but then there was issue #24241. :) trait From { + fn foo() {} } impl From for T { diff --git a/src/test/compile-fail/coherence-overlap-messages.rs b/src/test/compile-fail/coherence-overlap-messages.rs index 0ae8135221c21..a10deeafbe67e 100644 --- a/src/test/compile-fail/coherence-overlap-messages.rs +++ b/src/test/compile-fail/coherence-overlap-messages.rs @@ -8,22 +8,22 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -trait Foo {} +trait Foo { fn foo() {} } impl Foo for T {} impl Foo for U {} //~ ERROR conflicting implementations of trait `Foo`: -trait Bar {} +trait Bar { fn bar() {} } impl Bar for (T, u8) {} impl Bar for (u8, T) {} //~ ERROR conflicting implementations of trait `Bar` for type `(u8, u8)`: -trait Baz {} +trait Baz { fn baz() {} } impl Baz for T {} impl Baz for u8 {} //~ ERROR conflicting implementations of trait `Baz` for type `u8`: -trait Quux {} +trait Quux { fn quux() {} } impl Quux for T {} impl Quux for T {} //~ ERROR conflicting implementations of trait `Quux<_, _>`: diff --git a/src/test/compile-fail/coherence-projection-conflict-orphan.rs b/src/test/compile-fail/coherence-projection-conflict-orphan.rs index 3ed3549de89aa..784ff0cd5e0aa 100644 --- a/src/test/compile-fail/coherence-projection-conflict-orphan.rs +++ b/src/test/compile-fail/coherence-projection-conflict-orphan.rs @@ -15,7 +15,7 @@ // due to the orphan rules. Therefore, `A::Item` may yet turn out to // be `i32`. -pub trait Foo

{} +pub trait Foo

{ fn foo() {} } pub trait Bar { type Output: 'static; diff --git a/src/test/compile-fail/coherence-projection-conflict-ty-param.rs b/src/test/compile-fail/coherence-projection-conflict-ty-param.rs index f04902a70f68c..120d9046389a1 100644 --- a/src/test/compile-fail/coherence-projection-conflict-ty-param.rs +++ b/src/test/compile-fail/coherence-projection-conflict-ty-param.rs @@ -13,7 +13,7 @@ use std::marker::PhantomData; -pub trait Foo

{} +pub trait Foo

{ fn foo() {} } impl > Foo

for Option {} diff --git a/src/test/compile-fail/coherence-projection-conflict.rs b/src/test/compile-fail/coherence-projection-conflict.rs index 6d3ab32f06f43..3c32ab38b93dc 100644 --- a/src/test/compile-fail/coherence-projection-conflict.rs +++ b/src/test/compile-fail/coherence-projection-conflict.rs @@ -10,7 +10,7 @@ use std::marker::PhantomData; -pub trait Foo

{} +pub trait Foo

{ fn foo() {} } pub trait Bar { type Output: 'static; diff --git a/src/test/compile-fail/coherence_copy_like_err_fundamental_struct.rs b/src/test/compile-fail/coherence_copy_like_err_fundamental_struct.rs index fcd6e5c495207..9fbb7aa4cb1a7 100644 --- a/src/test/compile-fail/coherence_copy_like_err_fundamental_struct.rs +++ b/src/test/compile-fail/coherence_copy_like_err_fundamental_struct.rs @@ -20,7 +20,7 @@ extern crate coherence_copy_like_lib as lib; struct MyType { x: i32 } -trait MyTrait { } +trait MyTrait { fn foo() {} } impl MyTrait for T { } // `MyFundamentalStruct` is declared fundamental, so we can test that diff --git a/src/test/compile-fail/coherence_copy_like_err_fundamental_struct_ref.rs b/src/test/compile-fail/coherence_copy_like_err_fundamental_struct_ref.rs index b5c0a7fb5f564..2f6dca4f3c271 100644 --- a/src/test/compile-fail/coherence_copy_like_err_fundamental_struct_ref.rs +++ b/src/test/compile-fail/coherence_copy_like_err_fundamental_struct_ref.rs @@ -20,7 +20,7 @@ extern crate coherence_copy_like_lib as lib; struct MyType { x: i32 } -trait MyTrait { } +trait MyTrait { fn foo() {} } impl MyTrait for T { } // `MyFundamentalStruct` is declared fundamental, so we can test that diff --git a/src/test/compile-fail/coherence_copy_like_err_fundamental_struct_tuple.rs b/src/test/compile-fail/coherence_copy_like_err_fundamental_struct_tuple.rs index 8e3e3f31cb5f1..f424e8872010f 100644 --- a/src/test/compile-fail/coherence_copy_like_err_fundamental_struct_tuple.rs +++ b/src/test/compile-fail/coherence_copy_like_err_fundamental_struct_tuple.rs @@ -19,7 +19,7 @@ extern crate coherence_copy_like_lib as lib; struct MyType { x: i32 } -trait MyTrait { } +trait MyTrait { fn foo() {} } impl MyTrait for T { } diff --git a/src/test/compile-fail/coherence_copy_like_err_struct.rs b/src/test/compile-fail/coherence_copy_like_err_struct.rs index 35bc17b8e8870..04262e65c5a2a 100644 --- a/src/test/compile-fail/coherence_copy_like_err_struct.rs +++ b/src/test/compile-fail/coherence_copy_like_err_struct.rs @@ -17,7 +17,7 @@ extern crate coherence_copy_like_lib as lib; struct MyType { x: i32 } -trait MyTrait { } +trait MyTrait { fn foo() {} } impl MyTrait for T { } // `MyStruct` is not declared fundamental, therefore this would diff --git a/src/test/compile-fail/coherence_copy_like_err_tuple.rs b/src/test/compile-fail/coherence_copy_like_err_tuple.rs index a70cc92955fb0..378a70864f0ee 100644 --- a/src/test/compile-fail/coherence_copy_like_err_tuple.rs +++ b/src/test/compile-fail/coherence_copy_like_err_tuple.rs @@ -17,7 +17,7 @@ extern crate coherence_copy_like_lib as lib; struct MyType { x: i32 } -trait MyTrait { } +trait MyTrait { fn foo() {} } impl MyTrait for T { } // Tuples are not fundamental, therefore this would require that diff --git a/src/test/compile-fail/feature-gate-overlapping_marker_traits.rs b/src/test/compile-fail/feature-gate-overlapping_marker_traits.rs new file mode 100644 index 0000000000000..d2aa4e59b5ba9 --- /dev/null +++ b/src/test/compile-fail/feature-gate-overlapping_marker_traits.rs @@ -0,0 +1,19 @@ +// Copyright 2017 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. + +use std::fmt::{Debug, Display}; + +trait MyMarker {} + +impl MyMarker for T {} +impl MyMarker for T {} +//~^ ERROR E0119 + +fn main() {} diff --git a/src/test/compile-fail/overlap-marker-trait.rs b/src/test/compile-fail/overlap-marker-trait.rs new file mode 100644 index 0000000000000..a649ae25f34ea --- /dev/null +++ b/src/test/compile-fail/overlap-marker-trait.rs @@ -0,0 +1,41 @@ +// Copyright 2017 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 for RFC 1268: we allow overlapping impls of marker traits, +// that is, traits without items. In this case, a type `T` is +// `MyMarker` if it is either `Debug` or `Display`. This test just +// checks that we don't consider **all** types to be `MyMarker`. See +// also the companion test in +// `run-pass/overlap-permitted-for-marker-traits.rs`. + +#![feature(overlapping_marker_traits)] +#![feature(optin_builtin_traits)] + +use std::fmt::{Debug, Display}; + +trait Marker {} + +impl Marker for T {} +impl Marker for T {} + +fn is_marker() { } + +struct NotDebugOrDisplay; + +fn main() { + // Debug && Display: + is_marker::(); + + // Debug && !Display: + is_marker::>(); + + // !Debug && !Display + is_marker::(); //~ ERROR +} diff --git a/src/test/compile-fail/specialization/specialization-overlap.rs b/src/test/compile-fail/specialization/specialization-overlap.rs index f579817100107..ff12a82db5b7d 100644 --- a/src/test/compile-fail/specialization/specialization-overlap.rs +++ b/src/test/compile-fail/specialization/specialization-overlap.rs @@ -10,19 +10,19 @@ #![feature(specialization)] -trait Foo {} +trait Foo { fn foo() {} } impl Foo for T {} impl Foo for Vec {} //~ ERROR E0119 -trait Bar {} +trait Bar { fn bar() {} } impl Bar for (T, u8) {} impl Bar for (u8, T) {} //~ ERROR E0119 -trait Baz {} +trait Baz { fn baz() {} } impl Baz for u8 {} impl Baz for T {} //~ ERROR E0119 -trait Qux {} +trait Qux { fn qux() {} } impl Qux for T {} impl Qux for T {} //~ ERROR E0119 diff --git a/src/test/run-pass/overlap-doesnt-conflict-with-specialization.rs b/src/test/run-pass/overlap-doesnt-conflict-with-specialization.rs new file mode 100644 index 0000000000000..ed45d81c0d6a1 --- /dev/null +++ b/src/test/run-pass/overlap-doesnt-conflict-with-specialization.rs @@ -0,0 +1,27 @@ +// Copyright 2017 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. + +#![feature(overlapping_marker_traits)] +#![feature(specialization)] + +trait MyMarker {} + +impl MyMarker for T {} +impl MyMarker for Vec {} + +fn foo(t: T) -> T { + t +} + +fn main() { + assert_eq!(1, foo(1)); + assert_eq!(2.0, foo(2.0)); + assert_eq!(vec![1], foo(vec![1])); +} diff --git a/src/test/run-pass/overlap-permitted-for-marker-traits-neg.rs b/src/test/run-pass/overlap-permitted-for-marker-traits-neg.rs new file mode 100644 index 0000000000000..740d5d22ab507 --- /dev/null +++ b/src/test/run-pass/overlap-permitted-for-marker-traits-neg.rs @@ -0,0 +1,20 @@ +// Copyright 2017 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. + +#![feature(overlapping_marker_traits)] +#![feature(optin_builtin_traits)] + +// Overlapping negative impls for `MyStruct` are permitted: +struct MyStruct; +impl !Send for MyStruct {} +impl !Send for MyStruct {} + +fn main() { +} diff --git a/src/test/run-pass/overlap-permitted-for-marker-traits.rs b/src/test/run-pass/overlap-permitted-for-marker-traits.rs new file mode 100644 index 0000000000000..11a46299d8c83 --- /dev/null +++ b/src/test/run-pass/overlap-permitted-for-marker-traits.rs @@ -0,0 +1,36 @@ +// Copyright 2017 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. + +// Tests for RFC 1268: we allow overlapping impls of marker traits, +// that is, traits without items. In this case, a type `T` is +// `MyMarker` if it is either `Debug` or `Display`. + +#![feature(overlapping_marker_traits)] +#![feature(optin_builtin_traits)] + +use std::fmt::{Debug, Display}; + +trait MyMarker {} + +impl MyMarker for T {} +impl MyMarker for T {} + +fn foo(t: T) -> T { + t +} + +fn main() { + // Debug && Display: + assert_eq!(1, foo(1)); + assert_eq!(2.0, foo(2.0)); + + // Debug && !Display: + assert_eq!(vec![1], foo(vec![1])); +}