Skip to content

Implement RFC 1268 #40097

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 6 commits into from
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion src/librustc/traits/select.rs
Original file line number Diff line number Diff line change
@@ -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);
}
}

4 changes: 4 additions & 0 deletions src/librustc/traits/specialize/specialization_graph.rs
Original file line number Diff line number Diff line change
@@ -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);

19 changes: 19 additions & 0 deletions src/librustc/ty/mod.rs
Original file line number Diff line number Diff line change
@@ -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 {
3 changes: 3 additions & 0 deletions src/libsyntax/feature_gate.rs
Original file line number Diff line number Diff line change
@@ -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! (
2 changes: 1 addition & 1 deletion src/test/compile-fail/E0120.rs
Original file line number Diff line number Diff line change
@@ -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
1 change: 1 addition & 0 deletions src/test/compile-fail/auxiliary/trait_impl_conflict.rs
Original file line number Diff line number Diff line change
@@ -9,6 +9,7 @@
// except according to those terms.

pub trait Foo {
fn foo() {}
}

impl Foo for isize {
Original file line number Diff line number Diff line change
@@ -9,6 +9,7 @@
// except according to those terms.

#![feature(optin_builtin_traits)]
#![feature(overlapping_marker_traits)]

trait MyTrait {}

@@ -20,8 +21,8 @@ impl<T: MyTrait> !Send for TestType<T> {}
//~^ ERROR conflicting implementations of trait `std::marker::Send`

unsafe impl<T:'static> Send for TestType<T> {}
//~^ ERROR conflicting implementations of trait `std::marker::Send`

impl !Send for TestType<i32> {}
//~^ ERROR conflicting implementations of trait `std::marker::Send`

fn main() {}
2 changes: 1 addition & 1 deletion src/test/compile-fail/coherence-default-trait-impl.rs
Original file line number Diff line number Diff line change
@@ -10,7 +10,7 @@

#![feature(optin_builtin_traits)]

trait MyTrait {}
trait MyTrait { fn foo() {} }

impl MyTrait for .. {}
//~^ ERROR redundant default implementations of trait `MyTrait`
2 changes: 1 addition & 1 deletion src/test/compile-fail/coherence-impls-send.rs
Original file line number Diff line number Diff line change
@@ -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() {
}
Original file line number Diff line number Diff line change
@@ -10,7 +10,7 @@

// Test that you cannot *directly* dispatch on lifetime requirements

trait MyTrait {}
trait MyTrait { fn foo() {} }

impl<T> MyTrait for T {}
impl<T: 'static> MyTrait for T {} //~ ERROR E0119
1 change: 1 addition & 0 deletions src/test/compile-fail/coherence-overlap-all-t-and-tuple.rs
Original file line number Diff line number Diff line change
@@ -17,6 +17,7 @@
// Seems pretty basic, but then there was issue #24241. :)

trait From<U> {
fn foo() {}
}

impl <T> From<T> for T {
8 changes: 4 additions & 4 deletions src/test/compile-fail/coherence-overlap-messages.rs
Original file line number Diff line number Diff line change
@@ -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<T> Foo for T {}
impl<U> Foo for U {} //~ ERROR conflicting implementations of trait `Foo`:

trait Bar {}
trait Bar { fn bar() {} }

impl<T> Bar for (T, u8) {}
impl<T> Bar for (u8, T) {} //~ ERROR conflicting implementations of trait `Bar` for type `(u8, u8)`:

trait Baz<T> {}
trait Baz<T> { fn baz() {} }

impl<T> Baz<u8> for T {}
impl<T> Baz<T> for u8 {} //~ ERROR conflicting implementations of trait `Baz<u8>` for type `u8`:

trait Quux<U, V> {}
trait Quux<U, V> { fn quux() {} }

impl<T, U, V> Quux<U, V> for T {}
impl<T, U> Quux<U, U> for T {} //~ ERROR conflicting implementations of trait `Quux<_, _>`:
Original file line number Diff line number Diff line change
@@ -15,7 +15,7 @@
// due to the orphan rules. Therefore, `A::Item` may yet turn out to
// be `i32`.

pub trait Foo<P> {}
pub trait Foo<P> { fn foo() {} }

pub trait Bar {
type Output: 'static;
Original file line number Diff line number Diff line change
@@ -13,7 +13,7 @@

use std::marker::PhantomData;

pub trait Foo<P> {}
pub trait Foo<P> { fn foo() {} }

impl <P, T: Foo<P>> Foo<P> for Option<T> {}

2 changes: 1 addition & 1 deletion src/test/compile-fail/coherence-projection-conflict.rs
Original file line number Diff line number Diff line change
@@ -10,7 +10,7 @@

use std::marker::PhantomData;

pub trait Foo<P> {}
pub trait Foo<P> { fn foo() {} }

pub trait Bar {
type Output: 'static;
Original file line number Diff line number Diff line change
@@ -20,7 +20,7 @@ extern crate coherence_copy_like_lib as lib;

struct MyType { x: i32 }

trait MyTrait { }
trait MyTrait { fn foo() {} }
impl<T: lib::MyCopy> MyTrait for T { }

// `MyFundamentalStruct` is declared fundamental, so we can test that
Original file line number Diff line number Diff line change
@@ -20,7 +20,7 @@ extern crate coherence_copy_like_lib as lib;

struct MyType { x: i32 }

trait MyTrait { }
trait MyTrait { fn foo() {} }
impl<T: lib::MyCopy> MyTrait for T { }

// `MyFundamentalStruct` is declared fundamental, so we can test that
Original file line number Diff line number Diff line change
@@ -19,7 +19,7 @@ extern crate coherence_copy_like_lib as lib;

struct MyType { x: i32 }

trait MyTrait { }
trait MyTrait { fn foo() {} }

impl<T: lib::MyCopy> MyTrait for T { }

2 changes: 1 addition & 1 deletion src/test/compile-fail/coherence_copy_like_err_struct.rs
Original file line number Diff line number Diff line change
@@ -17,7 +17,7 @@ extern crate coherence_copy_like_lib as lib;

struct MyType { x: i32 }

trait MyTrait { }
trait MyTrait { fn foo() {} }
impl<T: lib::MyCopy> MyTrait for T { }

// `MyStruct` is not declared fundamental, therefore this would
2 changes: 1 addition & 1 deletion src/test/compile-fail/coherence_copy_like_err_tuple.rs
Original file line number Diff line number Diff line change
@@ -17,7 +17,7 @@ extern crate coherence_copy_like_lib as lib;

struct MyType { x: i32 }

trait MyTrait { }
trait MyTrait { fn foo() {} }
impl<T: lib::MyCopy> MyTrait for T { }

// Tuples are not fundamental, therefore this would require that
19 changes: 19 additions & 0 deletions src/test/compile-fail/feature-gate-overlapping_marker_traits.rs
Original file line number Diff line number Diff line change
@@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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<T: Display> MyMarker for T {}
impl<T: Debug> MyMarker for T {}
//~^ ERROR E0119

fn main() {}
41 changes: 41 additions & 0 deletions src/test/compile-fail/overlap-marker-trait.rs
Original file line number Diff line number Diff line change
@@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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<T: Debug> Marker for T {}
impl<T: Display> Marker for T {}

fn is_marker<T: Marker>() { }

struct NotDebugOrDisplay;

fn main() {
// Debug && Display:
is_marker::<i32>();

// Debug && !Display:
is_marker::<Vec<i32>>();

// !Debug && !Display
is_marker::<NotDebugOrDisplay>(); //~ ERROR
}
Original file line number Diff line number Diff line change
@@ -10,19 +10,19 @@

#![feature(specialization)]

trait Foo {}
trait Foo { fn foo() {} }
impl<T: Clone> Foo for T {}
impl<T> Foo for Vec<T> {} //~ ERROR E0119

trait Bar {}
trait Bar { fn bar() {} }
impl<T> Bar for (T, u8) {}
impl<T> Bar for (u8, T) {} //~ ERROR E0119

trait Baz<U> {}
trait Baz<U> { fn baz() {} }
impl<T> Baz<T> for u8 {}
impl<T> Baz<u8> for T {} //~ ERROR E0119

trait Qux {}
trait Qux { fn qux() {} }
impl<T: Clone> Qux for T {}
impl<T: Eq> Qux for T {} //~ ERROR E0119

27 changes: 27 additions & 0 deletions src/test/run-pass/overlap-doesnt-conflict-with-specialization.rs
Original file line number Diff line number Diff line change
@@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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<T> MyMarker for T {}
impl<T> MyMarker for Vec<T> {}

fn foo<T: MyMarker>(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]));
}
20 changes: 20 additions & 0 deletions src/test/run-pass/overlap-permitted-for-marker-traits-neg.rs
Original file line number Diff line number Diff line change
@@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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() {
}
36 changes: 36 additions & 0 deletions src/test/run-pass/overlap-permitted-for-marker-traits.rs
Original file line number Diff line number Diff line change
@@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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<T: Debug> MyMarker for T {}
impl<T: Display> MyMarker for T {}

fn foo<T: MyMarker>(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]));
}