Skip to content

Commit

Permalink
Generate documentation for auto-trait impls
Browse files Browse the repository at this point in the history
A new section is added to both both struct and trait doc pages.

On struct/enum pages, a new 'Auto Trait Implementations' section displays any
synthetic implementations for auto traits. Currently, this is only done
for Send and Sync.

On trait pages, a new 'Auto Implementors' section displays all types
which automatically implement the trait. Effectively, this is a list of
all public types in the standard library.

Synthesized impls for a particular auto trait ('synthetic impls') take
into account generic bounds. For example, a type 'struct Foo<T>(T)' will
have 'impl<T> Send for Foo<T> where T: Send' generated for it.

Manual implementations of auto traits are also taken into account. If we have
the following types:

'struct Foo<T>(T)'
'struct Wrapper<T>(Foo<T>)'
'unsafe impl<T> Send for Wrapper<T>' // pretend that Wrapper<T> makes
this sound somehow

Then Wrapper will have the following impl generated:
'impl<T> Send for Wrapper<T>'
reflecting the fact that 'T: Send' need not hold for 'Wrapper<T>: Send'
to hold

Lifetimes, HRTBS, and projections (e.g. '<T as Iterator>::Item') are
taken into account by synthetic impls

However, if a type can *never* implement a particular auto trait
(e.g. 'struct MyStruct<T>(*const T)'), then a negative impl will be
generated (in this case, 'impl<T> !Send for MyStruct<T>')

All of this means that a user should be able to copy-paste a synthetic
impl into their code, without any observable changes in behavior
(assuming the rest of the program remains unchanged).
  • Loading branch information
Aaron1011 committed Feb 18, 2018
1 parent 27a046e commit 6728f21
Show file tree
Hide file tree
Showing 29 changed files with 2,484 additions and 152 deletions.
2 changes: 1 addition & 1 deletion src/doc/rust-by-example
4 changes: 4 additions & 0 deletions src/librustc/hir/map/definitions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,10 @@ impl DefPathTable {
index
}

pub fn next_id(&self, address_space: DefIndexAddressSpace) -> DefIndex {
DefIndex::from_array_index(self.index_to_key[address_space.index()].len(), address_space)
}

#[inline(always)]
pub fn def_key(&self, index: DefIndex) -> DefKey {
self.index_to_key[index.address_space().index()]
Expand Down
13 changes: 11 additions & 2 deletions src/librustc/infer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,7 @@ pub struct InferCtxt<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
// for each body-id in this map, which will process the
// obligations within. This is expected to be done 'late enough'
// that all type inference variables have been bound and so forth.
region_obligations: RefCell<Vec<(ast::NodeId, RegionObligation<'tcx>)>>,
pub region_obligations: RefCell<Vec<(ast::NodeId, RegionObligation<'tcx>)>>,
}

/// A map returned by `skolemize_late_bound_regions()` indicating the skolemized
Expand Down Expand Up @@ -1555,11 +1555,20 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
InferOk { value, obligations }
}

fn borrow_region_constraints(&self) -> RefMut<'_, RegionConstraintCollector<'tcx>> {
pub fn borrow_region_constraints(&self) -> RefMut<'_, RegionConstraintCollector<'tcx>> {
RefMut::map(
self.region_constraints.borrow_mut(),
|c| c.as_mut().expect("region constraints already solved"))
}

/// Clears the selection, evaluation, and projection cachesThis is useful when
/// repeatedly attemping to select an Obligation while chagning only
/// its ParamEnv, since FulfillmentContext doesn't use 'probe'
pub fn clear_caches(&self) {
self.selection_cache.clear();
self.evaluation_cache.clear();
self.projection_cache.borrow_mut().clear();
}
}

impl<'a, 'gcx, 'tcx> TypeTrace<'tcx> {
Expand Down
10 changes: 7 additions & 3 deletions src/librustc/infer/region_constraints/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ pub type VarOrigins = IndexVec<RegionVid, RegionVariableOrigin>;
/// Describes constraints between the region variables and other
/// regions, as well as other conditions that must be verified, or
/// assumptions that can be made.
#[derive(Debug, Default)]
#[derive(Debug, Default, Clone)]
pub struct RegionConstraintData<'tcx> {
/// Constraints of the form `A <= B`, where either `A` or `B` can
/// be a region variable (or neither, as it happens).
Expand Down Expand Up @@ -142,7 +142,7 @@ pub enum Constraint<'tcx> {
/// outlive `RS`. Therefore verify that `R <= RS[i]` for some
/// `i`. Inference variables may be involved (but this verification
/// step doesn't influence inference).
#[derive(Debug)]
#[derive(Debug, Clone)]
pub struct Verify<'tcx> {
pub kind: GenericKind<'tcx>,
pub origin: SubregionOrigin<'tcx>,
Expand All @@ -159,7 +159,7 @@ pub enum GenericKind<'tcx> {
/// When we introduce a verification step, we wish to test that a
/// particular region (let's call it `'min`) meets some bound.
/// The bound is described the by the following grammar:
#[derive(Debug)]
#[derive(Debug, Clone)]
pub enum VerifyBound<'tcx> {
/// B = exists {R} --> some 'r in {R} must outlive 'min
///
Expand Down Expand Up @@ -288,6 +288,10 @@ impl<'tcx> RegionConstraintCollector<'tcx> {
&self.var_origins
}

pub fn region_constraint_data(&self) -> &RegionConstraintData<'tcx> {
&self.data
}

/// Once all the constraints have been gathered, extract out the final data.
///
/// Not legal during a snapshot.
Expand Down
4 changes: 2 additions & 2 deletions src/librustc/traits/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,8 @@ use syntax_pos::{Span, DUMMY_SP};
pub use self::coherence::{orphan_check, overlapping_impls, OrphanCheckErr, OverlapResult};
pub use self::fulfill::FulfillmentContext;
pub use self::project::MismatchedProjectionTypes;
pub use self::project::{normalize, normalize_projection_type, Normalized};
pub use self::project::{ProjectionCache, ProjectionCacheSnapshot, Reveal};
pub use self::project::{normalize, normalize_projection_type, poly_project_and_unify_type};
pub use self::project::{ProjectionCache, ProjectionCacheSnapshot, Reveal, Normalized};
pub use self::object_safety::ObjectSafetyViolation;
pub use self::object_safety::MethodViolationCode;
pub use self::on_unimplemented::{OnUnimplementedDirective, OnUnimplementedNote};
Expand Down
4 changes: 4 additions & 0 deletions src/librustc/traits/project.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1596,6 +1596,10 @@ impl<'tcx> ProjectionCache<'tcx> {
}
}

pub fn clear(&mut self) {
self.map.clear();
}

pub fn snapshot(&mut self) -> ProjectionCacheSnapshot {
ProjectionCacheSnapshot { snapshot: self.map.snapshot() }
}
Expand Down
31 changes: 30 additions & 1 deletion src/librustc/traits/select.rs
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,11 @@ pub struct SelectionContext<'cx, 'gcx: 'cx+'tcx, 'tcx: 'cx> {
inferred_obligations: SnapshotVec<InferredObligationsSnapshotVecDelegate<'tcx>>,

intercrate_ambiguity_causes: Option<Vec<IntercrateAmbiguityCause>>,

/// Controls whether or not to filter out negative impls when selecting.
/// This is used in librustdoc to distinguish between the lack of an impl
/// and a negative impl
allow_negative_impls: bool
}

#[derive(Clone, Debug)]
Expand Down Expand Up @@ -424,6 +429,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
intercrate: None,
inferred_obligations: SnapshotVec::new(),
intercrate_ambiguity_causes: None,
allow_negative_impls: false
}
}

Expand All @@ -436,6 +442,20 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
intercrate: Some(mode),
inferred_obligations: SnapshotVec::new(),
intercrate_ambiguity_causes: None,
allow_negative_impls: false
}
}

pub fn with_negative(infcx: &'cx InferCtxt<'cx, 'gcx, 'tcx>,
allow_negative_impls: bool) -> SelectionContext<'cx, 'gcx, 'tcx> {
debug!("with_negative({:?})", allow_negative_impls);
SelectionContext {
infcx,
freshener: infcx.freshener(),
intercrate: None,
inferred_obligations: SnapshotVec::new(),
intercrate_ambiguity_causes: Vec::new(),
allow_negative_impls
}
}

Expand Down Expand Up @@ -1086,7 +1106,8 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
fn filter_negative_impls(&self, candidate: SelectionCandidate<'tcx>)
-> SelectionResult<'tcx, SelectionCandidate<'tcx>> {
if let ImplCandidate(def_id) = candidate {
if self.tcx().impl_polarity(def_id) == hir::ImplPolarity::Negative {
if !self.allow_negative_impls &&
self.tcx().impl_polarity(def_id) == hir::ImplPolarity::Negative {
return Err(Unimplemented)
}
}
Expand Down Expand Up @@ -3337,6 +3358,10 @@ impl<'tcx> SelectionCache<'tcx> {
hashmap: RefCell::new(FxHashMap())
}
}

pub fn clear(&self) {
*self.hashmap.borrow_mut() = FxHashMap()
}
}

impl<'tcx> EvaluationCache<'tcx> {
Expand All @@ -3345,6 +3370,10 @@ impl<'tcx> EvaluationCache<'tcx> {
hashmap: RefCell::new(FxHashMap())
}
}

pub fn clear(&self) {
*self.hashmap.borrow_mut() = FxHashMap()
}
}

impl<'o,'tcx> TraitObligationStack<'o,'tcx> {
Expand Down
5 changes: 5 additions & 0 deletions src/librustc_data_structures/snapshot_map/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,11 @@ impl<K, V> SnapshotMap<K, V>
}
}

pub fn clear(&mut self) {
self.map.clear();
self.undo_log.clear();
}

pub fn insert(&mut self, key: K, value: V) -> bool {
match self.map.insert(key.clone(), value) {
None => {
Expand Down
Loading

0 comments on commit 6728f21

Please sign in to comment.