Skip to content
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

Rollup of 2 pull requests #41312

Merged
merged 14 commits into from
Apr 15, 2017
Merged
Show file tree
Hide file tree
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
1 change: 1 addition & 0 deletions src/doc/unstable-book/src/SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,7 @@
- [optin_builtin_traits](optin-builtin-traits.md)
- [option_entry](option-entry.md)
- [osstring_shrink_to_fit](osstring-shrink-to-fit.md)
- [overlapping_marker_traits](overlapping-marker-traits.md)
- [panic_abort](panic-abort.md)
- [panic_runtime](panic-runtime.md)
- [panic_unwind](panic-unwind.md)
Expand Down
7 changes: 7 additions & 0 deletions src/doc/unstable-book/src/overlapping-marker-traits.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# `overlapping_marker_traits`

The tracking issue for this feature is: [#29864]

[#29864]: https://github.com/rust-lang/rust/issues/29864

------------------------
197 changes: 164 additions & 33 deletions src/libcore/hash/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -107,29 +107,25 @@ mod sip;

/// A hashable type.
///
/// The `H` type parameter is an abstract hash state that is used by the `Hash`
/// to compute the hash.
/// Types implementing `Hash` are able to be [`hash`]ed with an instance of
/// [`Hasher`].
///
/// If you are also implementing [`Eq`], there is an additional property that
/// is important:
/// ## Implementing `Hash`
///
/// ```text
/// k1 == k2 -> hash(k1) == hash(k2)
/// ```
///
/// In other words, if two keys are equal, their hashes should also be equal.
/// [`HashMap`] and [`HashSet`] both rely on this behavior.
/// You can derive `Hash` with `#[derive(Hash)]` if all fields implement `Hash`.
/// The resulting hash will be the combination of the values from calling
/// [`hash`] on each field.
///
/// ## Derivable
///
/// This trait can be used with `#[derive]` if all fields implement `Hash`.
/// When `derive`d, the resulting hash will be the combination of the values
/// from calling [`.hash`] on each field.
///
/// ## How can I implement `Hash`?
/// ```
/// #[derive(Hash)]
/// struct Rustacean {
/// name: String,
/// country: String,
/// }
/// ```
///
/// If you need more control over how a value is hashed, you need to implement
/// the `Hash` trait:
/// If you need more control over how a value is hashed, you can of course
/// implement the `Hash` trait yourself:
///
/// ```
/// use std::hash::{Hash, Hasher};
Expand All @@ -148,17 +144,60 @@ mod sip;
/// }
/// ```
///
/// ## `Hash` and `Eq`
///
/// When implementing both `Hash` and [`Eq`], it is important that the following
/// property holds:
///
/// ```text
/// k1 == k2 -> hash(k1) == hash(k2)
/// ```
///
/// In other words, if two keys are equal, their hashes must also be equal.
/// [`HashMap`] and [`HashSet`] both rely on this behavior.
///
/// Thankfully, you won't need to worry about upholding this property when
/// deriving both [`Eq`] and `Hash` with `#[derive(PartialEq, Eq, Hash)]`.
///
/// [`Eq`]: ../../std/cmp/trait.Eq.html
/// [`Hasher`]: trait.Hasher.html
/// [`HashMap`]: ../../std/collections/struct.HashMap.html
/// [`HashSet`]: ../../std/collections/struct.HashSet.html
/// [`.hash`]: #tymethod.hash
/// [`hash`]: #tymethod.hash
#[stable(feature = "rust1", since = "1.0.0")]
pub trait Hash {
/// Feeds this value into the state given, updating the hasher as necessary.
/// Feeds this value into the given [`Hasher`].
///
/// # Examples
///
/// ```
/// use std::collections::hash_map::DefaultHasher;
/// use std::hash::{Hash, Hasher};
///
/// let mut hasher = DefaultHasher::new();
/// 7920.hash(&mut hasher);
/// println!("Hash is {:x}!", hasher.finish());
/// ```
///
/// [`Hasher`]: trait.Hasher.html
#[stable(feature = "rust1", since = "1.0.0")]
fn hash<H: Hasher>(&self, state: &mut H);

/// Feeds a slice of this type into the state provided.
/// Feeds a slice of this type into the given [`Hasher`].
///
/// # Examples
///
/// ```
/// use std::collections::hash_map::DefaultHasher;
/// use std::hash::{Hash, Hasher};
///
/// let mut hasher = DefaultHasher::new();
/// let numbers = [6, 28, 496, 8128];
/// Hash::hash_slice(&numbers, &mut hasher);
/// println!("Hash is {:x}!", hasher.finish());
/// ```
///
/// [`Hasher`]: trait.Hasher.html
#[stable(feature = "hash_slice", since = "1.3.0")]
fn hash_slice<H: Hasher>(data: &[Self], state: &mut H)
where Self: Sized
Expand All @@ -169,18 +208,73 @@ pub trait Hash {
}
}

/// A trait which represents the ability to hash an arbitrary stream of bytes.
/// A trait for hashing an arbitrary stream of bytes.
///
/// Instances of `Hasher` usually represent state that is changed while hashing
/// data.
///
/// `Hasher` provides a fairly basic interface for retrieving the generated hash
/// (with [`finish`]), and writing integers as well as slices of bytes into an
/// instance (with [`write`] and [`write_u8`] etc.). Most of the time, `Hasher`
/// instances are used in conjunction with the [`Hash`] trait.
///
/// # Examples
///
/// ```
/// use std::collections::hash_map::DefaultHasher;
/// use std::hash::Hasher;
///
/// let mut hasher = DefaultHasher::new();
///
/// hasher.write_u32(1989);
/// hasher.write_u8(11);
/// hasher.write_u8(9);
/// hasher.write(b"Huh?");
///
/// println!("Hash is {:x}!", hasher.finish());
/// ```
///
/// [`Hash`]: trait.Hash.html
/// [`finish`]: #tymethod.finish
/// [`write`]: #tymethod.write
/// [`write_u8`]: #method.write_u8
#[stable(feature = "rust1", since = "1.0.0")]
pub trait Hasher {
/// Completes a round of hashing, producing the output hash generated.
///
/// # Examples
///
/// ```
/// use std::collections::hash_map::DefaultHasher;
/// use std::hash::Hasher;
///
/// let mut hasher = DefaultHasher::new();
/// hasher.write(b"Cool!");
///
/// println!("Hash is {:x}!", hasher.finish());
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
fn finish(&self) -> u64;

/// Writes some data into this `Hasher`.
///
/// # Examples
///
/// ```
/// use std::collections::hash_map::DefaultHasher;
/// use std::hash::Hasher;
///
/// let mut hasher = DefaultHasher::new();
/// let data = [0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef];
///
/// hasher.write(&data);
///
/// println!("Hash is {:x}!", hasher.finish());
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
fn write(&mut self, bytes: &[u8]);

/// Write a single `u8` into this hasher.
/// Writes a single `u8` into this hasher.
#[inline]
#[stable(feature = "hasher_write", since = "1.3.0")]
fn write_u8(&mut self, i: u8) {
Expand Down Expand Up @@ -258,12 +352,35 @@ pub trait Hasher {
}
}

/// A `BuildHasher` is typically used as a factory for instances of `Hasher`
/// which a `HashMap` can then use to hash keys independently.
/// A trait for creating instances of [`Hasher`].
///
/// A `BuildHasher` is typically used (e.g. by [`HashMap`]) to create
/// [`Hasher`]s for each key such that they are hashed independently of one
/// another, since [`Hasher`]s contain state.
///
/// For each instance of `BuildHasher`, the [`Hasher`]s created by
/// [`build_hasher`] should be identical. That is, if the same stream of bytes
/// is fed into each hasher, the same output will also be generated.
///
/// # Examples
///
/// ```
/// use std::collections::hash_map::RandomState;
/// use std::hash::{BuildHasher, Hasher};
///
/// let s = RandomState::new();
/// let mut hasher_1 = s.build_hasher();
/// let mut hasher_2 = s.build_hasher();
///
/// Note that for each instance of `BuildHasher`, the created hashers should be
/// identical. That is, if the same stream of bytes is fed into each hasher, the
/// same output will also be generated.
/// hasher_1.write_u32(8128);
/// hasher_2.write_u32(8128);
///
/// assert_eq!(hasher_1.finish(), hasher_2.finish());
/// ```
///
/// [`build_hasher`]: #tymethod.build_hasher
/// [`Hasher`]: trait.Hasher.html
/// [`HashMap`]: ../../std/collections/struct.HashMap.html
#[stable(since = "1.7.0", feature = "build_hasher")]
pub trait BuildHasher {
/// Type of the hasher that will be created.
Expand All @@ -272,6 +389,9 @@ pub trait BuildHasher {

/// Creates a new hasher.
///
/// Each call to `build_hasher` on the same instance should produce identical
/// [`Hasher`]s.
///
/// # Examples
///
/// ```
Expand All @@ -281,15 +401,23 @@ pub trait BuildHasher {
/// let s = RandomState::new();
/// let new_s = s.build_hasher();
/// ```
///
/// [`Hasher`]: trait.Hasher.html
#[stable(since = "1.7.0", feature = "build_hasher")]
fn build_hasher(&self) -> Self::Hasher;
}

/// The `BuildHasherDefault` structure is used in scenarios where one has a
/// type that implements [`Hasher`] and [`Default`], but needs that type to
/// implement [`BuildHasher`].
/// Used to create a default [`BuildHasher`] instance for types that implement
/// [`Hasher`] and [`Default`].
///
/// This structure is zero-sized and does not need construction.
/// `BuildHasherDefault<H>` can be used when a type `H` implements [`Hasher`] and
/// [`Default`], and you need a corresponding [`BuildHasher`] instance, but none is
/// defined.
///
/// Any `BuildHasherDefault` is [zero-sized]. It can be created with
/// [`default`][method.Default]. When using `BuildHasherDefault` with [`HashMap`] or
/// [`HashSet`], this doesn't need to be done, since they implement appropriate
/// [`Default`] instances themselves.
///
/// # Examples
///
Expand Down Expand Up @@ -322,8 +450,11 @@ pub trait BuildHasher {
///
/// [`BuildHasher`]: trait.BuildHasher.html
/// [`Default`]: ../default/trait.Default.html
/// [method.default]: #method.default
/// [`Hasher`]: trait.Hasher.html
/// [`HashMap`]: ../../std/collections/struct.HashMap.html
/// [`HashSet`]: ../../std/collections/struct.HashSet.html
/// [zero-sized]: https://doc.rust-lang.org/nomicon/exotic-sizes.html#zero-sized-types-zsts
#[stable(since = "1.7.0", feature = "build_hasher")]
pub struct BuildHasherDefault<H>(marker::PhantomData<H>);

Expand Down
3 changes: 2 additions & 1 deletion src/librustc/traits/select.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1736,7 +1736,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 @@ -2227,6 +2227,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 @@ -349,6 +349,9 @@ declare_features! (

// Allows module-level inline assembly by way of global_asm!()
(active, global_asm, "1.18.0", Some(35119)),

// 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
Loading