Skip to content

Commit

Permalink
Rollup merge of rust-lang#40097 - sgrif:sg-implement-rfc-1268, r=niko…
Browse files Browse the repository at this point in the history
…matsakis

Implement RFC 1268

This patch allows overlap to occur between any two impls of a trait for
traits which have no associated items.

Several compile-fail tests around coherence had to be changed to add at
least one item to the trait they test against.

Ref rust-lang#29864
  • Loading branch information
frewsxcv authored Apr 4, 2017
2 parents 2564711 + 665f852 commit 2c4df77
Show file tree
Hide file tree
Showing 26 changed files with 195 additions and 22 deletions.
3 changes: 2 additions & 1 deletion src/librustc/traits/select.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}

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

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

pub trait Foo {
fn foo() {}
}

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

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

trait MyTrait {}

Expand All @@ -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
Expand Up @@ -10,7 +10,7 @@

#![feature(optin_builtin_traits)]

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

impl MyTrait for .. {}
//~^ ERROR redundant default implementations of trait `MyTrait`
Expand Down
2 changes: 1 addition & 1 deletion src/test/compile-fail/coherence-impls-send.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
// except according to those terms.

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

use std::marker::Copy;

Expand All @@ -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
Expand Up @@ -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
Expand Down
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
Expand Up @@ -17,6 +17,7 @@
// Seems pretty basic, but then there was issue #24241. :)

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

impl <T> From<T> for T {
Expand Down
8 changes: 4 additions & 4 deletions src/test/compile-fail/coherence-overlap-messages.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<_, _>`:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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> {}

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

use std::marker::PhantomData;

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

pub trait Bar {
type Output: 'static;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 { }

Expand Down
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
Expand Up @@ -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
Expand Down
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
Expand Up @@ -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
Expand Down
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
Expand Up @@ -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

Expand Down
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() {
}
Loading

0 comments on commit 2c4df77

Please sign in to comment.