CoherenceCheckImpl(D),
CoherenceOverlapCheck(D),
CoherenceOverlapCheckSpecial(D),
- CoherenceOverlapInherentCheck(D),
CoherenceOrphanCheck(D),
Variance,
WfCheck(D),
CoherenceCheckImpl(ref d) => op(d).map(CoherenceCheckImpl),
CoherenceOverlapCheck(ref d) => op(d).map(CoherenceOverlapCheck),
CoherenceOverlapCheckSpecial(ref d) => op(d).map(CoherenceOverlapCheckSpecial),
- CoherenceOverlapInherentCheck(ref d) => op(d).map(CoherenceOverlapInherentCheck),
CoherenceOrphanCheck(ref d) => op(d).map(CoherenceOrphanCheck),
WfCheck(ref d) => op(d).map(WfCheck),
TypeckItemType(ref d) => op(d).map(TypeckItemType),
pub fn keys(&self) -> Vec<M::Key> {
self.map.keys().cloned().collect()
}
-
- /// Append `elem` to the vector stored for `k`, creating a new vector if needed.
- /// This is considered a write to `k`.
- ///
- /// NOTE: Caution is required when using this method. You should
- /// be sure that nobody is **reading from the vector** while you
- /// are writing to it. Eventually, it'd be nice to remove this.
- pub fn push<E: Clone>(&mut self, k: M::Key, elem: E)
- where M: DepTrackingMapConfig<Value=Vec<E>>
- {
- self.write(&k);
- self.map.entry(k)
- .or_insert(Vec::new())
- .push(elem);
- }
}
impl<M: DepTrackingMapConfig> MemoizationMap for RefCell<DepTrackingMap<M>> {
fn item_generics_cloned(&self, def: DefId) -> ty::Generics;
fn item_attrs(&self, def_id: DefId) -> Vec<ast::Attribute>;
fn fn_arg_names(&self, did: DefId) -> Vec<ast::Name>;
- fn inherent_implementations_for_type(&self, def_id: DefId) -> Vec<DefId>;
// trait info
fn implementations_of_trait(&self, filter: Option<DefId>) -> Vec<DefId>;
{ bug!("item_generics_cloned") }
fn item_attrs(&self, def_id: DefId) -> Vec<ast::Attribute> { bug!("item_attrs") }
fn fn_arg_names(&self, did: DefId) -> Vec<ast::Name> { bug!("fn_arg_names") }
- fn inherent_implementations_for_type(&self, def_id: DefId) -> Vec<DefId> { vec![] }
// trait info
fn implementations_of_trait(&self, filter: Option<DefId>) -> Vec<DefId> { vec![] }
use hir::def_id::{CrateNum, DefId, LOCAL_CRATE};
use middle::const_val::ConstVal;
use mir;
-use ty::{self, Ty, TyCtxt};
+use ty::{self, CrateInherentImpls, Ty, TyCtxt};
use rustc_data_structures::indexed_vec::IndexVec;
use std::cell::{RefCell, RefMut};
}
}
-impl<'tcx> QueryDescription for queries::coherent_inherent_impls<'tcx> {
+impl<'tcx> QueryDescription for queries::crate_inherent_impls<'tcx> {
+ fn describe(_: TyCtxt, k: CrateNum) -> String {
+ format!("all inherent impls defined in crate `{:?}`", k)
+ }
+}
+
+impl<'tcx> QueryDescription for queries::crate_inherent_impls_overlap_check<'tcx> {
fn describe(_: TyCtxt, _: CrateNum) -> String {
- format!("coherence checking all inherent impls")
+ format!("check for overlap between inherent impls defined in this crate")
}
}
/// Maps a DefId of a type to a list of its inherent impls.
/// Contains implementations of methods that are inherent to a type.
/// Methods in these implementations don't need to be exported.
- pub inherent_impls: InherentImpls(DefId) -> Vec<DefId>,
+ pub inherent_impls: InherentImpls(DefId) -> Rc<Vec<DefId>>,
/// Maps from the def-id of a function/method or const/static
/// to its MIR. Mutation is done at an item granularity to
pub coherent_trait: coherent_trait_dep_node((CrateNum, DefId)) -> (),
- pub coherent_inherent_impls: coherent_inherent_impls_dep_node(CrateNum) -> (),
+ /// Gets a complete map from all types to their inherent impls.
+ /// Not meant to be used directly outside of coherence.
+ /// (Defined only for LOCAL_CRATE)
+ pub crate_inherent_impls: crate_inherent_impls_dep_node(CrateNum) -> CrateInherentImpls,
+
+ /// Checks all types in the krate for overlap in their inherent impls. Reports errors.
+ /// Not meant to be used directly outside of coherence.
+ /// (Defined only for LOCAL_CRATE)
+ pub crate_inherent_impls_overlap_check: crate_inherent_impls_dep_node(CrateNum) -> (),
/// Results of evaluating monomorphic constants embedded in
/// other items, such as enum variant explicit discriminants.
DepNode::CoherenceCheckTrait(def_id)
}
-fn coherent_inherent_impls_dep_node(_: CrateNum) -> DepNode<DefId> {
+fn crate_inherent_impls_dep_node(_: CrateNum) -> DepNode<DefId> {
DepNode::Coherence
}
use ty::util::IntTypeExt;
use ty::walk::TypeWalker;
use util::common::MemoizationMap;
-use util::nodemap::{NodeSet, FxHashMap};
+use util::nodemap::{NodeSet, DefIdMap, FxHashMap};
use serialize::{self, Encodable, Encoder};
use std::borrow::Cow;
def.flags.get().intersects(TraitFlags::HAS_DEFAULT_IMPL)
}
- /// Populates the type context with all the inherent implementations for
- /// the given type if necessary.
- pub fn populate_inherent_implementations_for_type_if_necessary(self,
- span: Span,
- type_id: DefId) {
- if type_id.is_local() {
- // Make sure coherence of inherent impls ran already.
- ty::queries::coherent_inherent_impls::force(self, span, LOCAL_CRATE);
- return
- }
-
- // The type is not local, hence we are reading this out of
- // metadata and don't need to track edges.
- let _ignore = self.dep_graph.in_ignore();
-
- if self.populated_external_types.borrow().contains(&type_id) {
- return
- }
-
- debug!("populate_inherent_implementations_for_type_if_necessary: searching for {:?}",
- type_id);
-
- let inherent_impls = self.sess.cstore.inherent_implementations_for_type(type_id);
-
- self.maps.inherent_impls.borrow_mut().insert(type_id, inherent_impls);
- self.populated_external_types.borrow_mut().insert(type_id);
- }
-
/// Populates the type context with all the implementations for the given
/// trait if necessary.
pub fn populate_implementations_for_trait_if_necessary(self, trait_id: DefId) {
..*providers
};
}
+
+
+/// A map for the local crate mapping each type to a vector of its
+/// inherent impls. This is not meant to be used outside of coherence;
+/// rather, you should request the vector for a specific type via
+/// `ty::queries::inherent_impls::get(def_id)` so as to minimize your
+/// dependencies (constructing this map requires touching the entire
+/// crate).
+#[derive(Clone, Debug)]
+pub struct CrateInherentImpls {
+ pub inherent_impls: DefIdMap<Rc<Vec<DefId>>>,
+}
+
typeck_tables => { cdata.item_body_tables(def_id.index, tcx) }
closure_kind => { cdata.closure_kind(def_id.index) }
closure_type => { cdata.closure_ty(def_id.index, tcx) }
+ inherent_impls => { Rc::new(cdata.get_inherent_implementations_for_type(def_id.index)) }
}
impl CrateStore for cstore::CStore {
self.get_crate_data(did.krate).get_fn_arg_names(did.index)
}
- fn inherent_implementations_for_type(&self, def_id: DefId) -> Vec<DefId>
- {
- self.dep_graph.read(DepNode::MetaData(def_id));
- self.get_crate_data(def_id.krate).get_inherent_implementations_for_type(def_id.index)
- }
-
fn implementations_of_trait(&self, filter: Option<DefId>) -> Vec<DefId>
{
if let Some(def_id) = filter {
}
fn assemble_inherent_impl_candidates_for_type(&mut self, def_id: DefId) {
- // Read the inherent implementation candidates for this type from the
- // metadata if necessary.
- self.tcx.populate_inherent_implementations_for_type_if_necessary(self.span, def_id);
-
- if let Some(impl_infos) = self.tcx.maps.inherent_impls.borrow().get(&def_id) {
- for &impl_def_id in impl_infos.iter() {
- self.assemble_inherent_impl_probe(impl_def_id);
- }
+ let impl_def_ids = ty::queries::inherent_impls::get(self.tcx, self.span, def_id);
+ for &impl_def_id in impl_def_ids.iter() {
+ self.assemble_inherent_impl_probe(impl_def_id);
}
}
+++ /dev/null
-// 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 rustc::dep_graph::DepNode;
-use rustc::hir::def_id::DefId;
-use rustc::hir;
-use rustc::hir::itemlikevisit::ItemLikeVisitor;
-use rustc::lint;
-use rustc::traits::{self, Reveal};
-use rustc::ty::{self, TyCtxt};
-
-use syntax::ast;
-use syntax_pos::Span;
-
-pub fn check<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
- tcx.visit_all_item_likes_in_krate(DepNode::CoherenceCheckImpl,
- &mut InherentCollect { tcx });
- tcx.visit_all_item_likes_in_krate(DepNode::CoherenceOverlapCheckSpecial,
- &mut InherentOverlapChecker { tcx });
-}
-
-struct InherentCollect<'a, 'tcx: 'a> {
- tcx: TyCtxt<'a, 'tcx, 'tcx>
-}
-
-impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for InherentCollect<'a, 'tcx> {
- fn visit_item(&mut self, item: &hir::Item) {
- let (unsafety, ty) = match item.node {
- hir::ItemImpl(unsafety, .., None, ref ty, _) => (unsafety, ty),
- _ => return
- };
-
- match unsafety {
- hir::Unsafety::Normal => {
- // OK
- }
- hir::Unsafety::Unsafe => {
- span_err!(self.tcx.sess,
- item.span,
- E0197,
- "inherent impls cannot be declared as unsafe");
- }
- }
-
- let def_id = self.tcx.hir.local_def_id(item.id);
- let self_ty = self.tcx.item_type(def_id);
- match self_ty.sty {
- ty::TyAdt(def, _) => {
- self.check_def_id(item, def.did);
- }
- ty::TyDynamic(ref data, ..) if data.principal().is_some() => {
- self.check_def_id(item, data.principal().unwrap().def_id());
- }
- ty::TyChar => {
- self.check_primitive_impl(def_id,
- self.tcx.lang_items.char_impl(),
- "char",
- "char",
- item.span);
- }
- ty::TyStr => {
- self.check_primitive_impl(def_id,
- self.tcx.lang_items.str_impl(),
- "str",
- "str",
- item.span);
- }
- ty::TySlice(_) => {
- self.check_primitive_impl(def_id,
- self.tcx.lang_items.slice_impl(),
- "slice",
- "[T]",
- item.span);
- }
- ty::TyRawPtr(ty::TypeAndMut { ty: _, mutbl: hir::MutImmutable }) => {
- self.check_primitive_impl(def_id,
- self.tcx.lang_items.const_ptr_impl(),
- "const_ptr",
- "*const T",
- item.span);
- }
- ty::TyRawPtr(ty::TypeAndMut { ty: _, mutbl: hir::MutMutable }) => {
- self.check_primitive_impl(def_id,
- self.tcx.lang_items.mut_ptr_impl(),
- "mut_ptr",
- "*mut T",
- item.span);
- }
- ty::TyInt(ast::IntTy::I8) => {
- self.check_primitive_impl(def_id,
- self.tcx.lang_items.i8_impl(),
- "i8",
- "i8",
- item.span);
- }
- ty::TyInt(ast::IntTy::I16) => {
- self.check_primitive_impl(def_id,
- self.tcx.lang_items.i16_impl(),
- "i16",
- "i16",
- item.span);
- }
- ty::TyInt(ast::IntTy::I32) => {
- self.check_primitive_impl(def_id,
- self.tcx.lang_items.i32_impl(),
- "i32",
- "i32",
- item.span);
- }
- ty::TyInt(ast::IntTy::I64) => {
- self.check_primitive_impl(def_id,
- self.tcx.lang_items.i64_impl(),
- "i64",
- "i64",
- item.span);
- }
- ty::TyInt(ast::IntTy::I128) => {
- self.check_primitive_impl(def_id,
- self.tcx.lang_items.i128_impl(),
- "i128",
- "i128",
- item.span);
- }
- ty::TyInt(ast::IntTy::Is) => {
- self.check_primitive_impl(def_id,
- self.tcx.lang_items.isize_impl(),
- "isize",
- "isize",
- item.span);
- }
- ty::TyUint(ast::UintTy::U8) => {
- self.check_primitive_impl(def_id,
- self.tcx.lang_items.u8_impl(),
- "u8",
- "u8",
- item.span);
- }
- ty::TyUint(ast::UintTy::U16) => {
- self.check_primitive_impl(def_id,
- self.tcx.lang_items.u16_impl(),
- "u16",
- "u16",
- item.span);
- }
- ty::TyUint(ast::UintTy::U32) => {
- self.check_primitive_impl(def_id,
- self.tcx.lang_items.u32_impl(),
- "u32",
- "u32",
- item.span);
- }
- ty::TyUint(ast::UintTy::U64) => {
- self.check_primitive_impl(def_id,
- self.tcx.lang_items.u64_impl(),
- "u64",
- "u64",
- item.span);
- }
- ty::TyUint(ast::UintTy::U128) => {
- self.check_primitive_impl(def_id,
- self.tcx.lang_items.u128_impl(),
- "u128",
- "u128",
- item.span);
- }
- ty::TyUint(ast::UintTy::Us) => {
- self.check_primitive_impl(def_id,
- self.tcx.lang_items.usize_impl(),
- "usize",
- "usize",
- item.span);
- }
- ty::TyFloat(ast::FloatTy::F32) => {
- self.check_primitive_impl(def_id,
- self.tcx.lang_items.f32_impl(),
- "f32",
- "f32",
- item.span);
- }
- ty::TyFloat(ast::FloatTy::F64) => {
- self.check_primitive_impl(def_id,
- self.tcx.lang_items.f64_impl(),
- "f64",
- "f64",
- item.span);
- }
- ty::TyError => {
- return;
- }
- _ => {
- struct_span_err!(self.tcx.sess,
- ty.span,
- E0118,
- "no base type found for inherent implementation")
- .span_label(ty.span, &format!("impl requires a base type"))
- .note(&format!("either implement a trait on it or create a newtype \
- to wrap it instead"))
- .emit();
- return;
- }
- }
- }
-
- fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem) {
- }
-
- fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) {
- }
-}
-
-impl<'a, 'tcx> InherentCollect<'a, 'tcx> {
- fn check_def_id(&self, item: &hir::Item, def_id: DefId) {
- if def_id.is_local() {
- // Add the implementation to the mapping from implementation to base
- // type def ID, if there is a base type for this implementation and
- // the implementation does not have any associated traits.
- let impl_def_id = self.tcx.hir.local_def_id(item.id);
-
- // Subtle: it'd be better to collect these into a local map
- // and then write the vector only once all items are known,
- // but that leads to degenerate dep-graphs. The problem is
- // that the write of that big vector winds up having reads
- // from *all* impls in the krate, since we've lost the
- // precision basically. This would be ok in the firewall
- // model so once we've made progess towards that we can modify
- // the strategy here. In the meantime, using `push` is ok
- // because we are doing this as a pre-pass before anyone
- // actually reads from `inherent_impls` -- and we know this is
- // true beacuse we hold the refcell lock.
- self.tcx.maps.inherent_impls.borrow_mut().push(def_id, impl_def_id);
- } else {
- struct_span_err!(self.tcx.sess,
- item.span,
- E0116,
- "cannot define inherent `impl` for a type outside of the crate \
- where the type is defined")
- .span_label(item.span,
- &format!("impl for type defined outside of crate."))
- .note("define and implement a trait or new type instead")
- .emit();
- }
- }
-
- fn check_primitive_impl(&self,
- impl_def_id: DefId,
- lang_def_id: Option<DefId>,
- lang: &str,
- ty: &str,
- span: Span) {
- match lang_def_id {
- Some(lang_def_id) if lang_def_id == impl_def_id => {
- // OK
- }
- _ => {
- struct_span_err!(self.tcx.sess,
- span,
- E0390,
- "only a single inherent implementation marked with `#[lang = \
- \"{}\"]` is allowed for the `{}` primitive",
- lang,
- ty)
- .span_help(span, "consider using a trait to implement these methods")
- .emit();
- }
- }
- }
-}
-
-struct InherentOverlapChecker<'a, 'tcx: 'a> {
- tcx: TyCtxt<'a, 'tcx, 'tcx>
-}
-
-impl<'a, 'tcx> InherentOverlapChecker<'a, 'tcx> {
- fn check_for_common_items_in_impls(&self, impl1: DefId, impl2: DefId) {
- #[derive(Copy, Clone, PartialEq)]
- enum Namespace {
- Type,
- Value,
- }
-
- let name_and_namespace = |def_id| {
- let item = self.tcx.associated_item(def_id);
- (item.name, match item.kind {
- ty::AssociatedKind::Type => Namespace::Type,
- ty::AssociatedKind::Const |
- ty::AssociatedKind::Method => Namespace::Value,
- })
- };
-
- let impl_items1 = self.tcx.associated_item_def_ids(impl1);
- let impl_items2 = self.tcx.associated_item_def_ids(impl2);
-
- for &item1 in &impl_items1[..] {
- let (name, namespace) = name_and_namespace(item1);
-
- for &item2 in &impl_items2[..] {
- if (name, namespace) == name_and_namespace(item2) {
- let msg = format!("duplicate definitions with name `{}`", name);
- let node_id = self.tcx.hir.as_local_node_id(item1).unwrap();
- self.tcx.sess.add_lint(lint::builtin::OVERLAPPING_INHERENT_IMPLS,
- node_id,
- self.tcx.span_of_impl(item1).unwrap(),
- msg);
- }
- }
- }
- }
-
- fn check_for_overlapping_inherent_impls(&self, ty_def_id: DefId) {
- let _task = self.tcx.dep_graph.in_task(DepNode::CoherenceOverlapInherentCheck(ty_def_id));
-
- let inherent_impls = self.tcx.maps.inherent_impls.borrow();
- let impls = match inherent_impls.get(&ty_def_id) {
- Some(impls) => impls,
- None => return,
- };
-
- for (i, &impl1_def_id) in impls.iter().enumerate() {
- for &impl2_def_id in &impls[(i + 1)..] {
- self.tcx.infer_ctxt((), Reveal::UserFacing).enter(|infcx| {
- if traits::overlapping_impls(&infcx, impl1_def_id, impl2_def_id).is_some() {
- self.check_for_common_items_in_impls(impl1_def_id, impl2_def_id)
- }
- });
- }
- }
- }
-}
-
-impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for InherentOverlapChecker<'a, 'tcx> {
- fn visit_item(&mut self, item: &'v hir::Item) {
- match item.node {
- hir::ItemEnum(..) |
- hir::ItemStruct(..) |
- hir::ItemTrait(..) |
- hir::ItemUnion(..) => {
- let type_def_id = self.tcx.hir.local_def_id(item.id);
- self.check_for_overlapping_inherent_impls(type_def_id);
- }
- _ => {}
- }
- }
-
- fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem) {
- }
-
- fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) {
- }
-}
-
--- /dev/null
+// 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.
+
+//! The code in this module gathers up all of the inherent impls in
+//! the current crate and organizes them in a map. It winds up
+//! touching the whole crate and thus must be recomputed completely
+//! for any change, but it is very cheap to compute. In practice, most
+//! code in the compiler never *directly* requests this map. Instead,
+//! it requests the inherent impls specific to some type (via
+//! `ty::queries::inherent_impls::get(def_id)`). That value, however,
+//! is computed by selecting an idea from this table.
+
+use rustc::dep_graph::DepNode;
+use rustc::hir::def_id::{CrateNum, DefId, LOCAL_CRATE};
+use rustc::hir;
+use rustc::hir::itemlikevisit::ItemLikeVisitor;
+use rustc::ty::{self, CrateInherentImpls, TyCtxt};
+use rustc::util::nodemap::DefIdMap;
+
+use std::rc::Rc;
+use syntax::ast;
+use syntax_pos::{DUMMY_SP, Span};
+
+/// On-demand query: yields a map containing all types mapped to their inherent impls.
+pub fn crate_inherent_impls<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+ crate_num: CrateNum)
+ -> CrateInherentImpls {
+ assert_eq!(crate_num, LOCAL_CRATE);
+
+ let krate = tcx.hir.krate();
+ let mut collect = InherentCollect {
+ tcx,
+ impls_map: CrateInherentImpls {
+ inherent_impls: DefIdMap()
+ }
+ };
+ krate.visit_all_item_likes(&mut collect);
+ collect.impls_map
+}
+
+/// On-demand query: yields a vector of the inherent impls for a specific type.
+pub fn inherent_impls<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+ ty_def_id: DefId)
+ -> Rc<Vec<DefId>> {
+ assert!(ty_def_id.is_local());
+
+ // NB. Until we adopt the red-green dep-tracking algorithm (see
+ // [the plan] for details on that), we do some hackery here to get
+ // the dependencies correct. Basically, we use a `with_ignore` to
+ // read the result we want. If we didn't have the `with_ignore`,
+ // we would wind up with a dependency on the entire crate, which
+ // we don't want. Then we go and add dependencies on all the impls
+ // in the result (which is what we wanted).
+ //
+ // The result is a graph with an edge from `Hir(I)` for every impl
+ // `I` defined on some type `T` to `CoherentInherentImpls(T)`,
+ // thus ensuring that if any of those impls change, the set of
+ // inherent impls is considered dirty.
+ //
+ // [the plan]: https://github.com/rust-lang/rust-roadmap/issues/4
+
+ let result = tcx.dep_graph.with_ignore(|| {
+ let crate_map = ty::queries::crate_inherent_impls::get(tcx, DUMMY_SP, ty_def_id.krate);
+ match crate_map.inherent_impls.get(&ty_def_id) {
+ Some(v) => v.clone(),
+ None => Rc::new(vec![]),
+ }
+ });
+
+ for &impl_def_id in &result[..] {
+ tcx.dep_graph.read(DepNode::Hir(impl_def_id));
+ }
+
+ result
+}
+
+struct InherentCollect<'a, 'tcx: 'a> {
+ tcx: TyCtxt<'a, 'tcx, 'tcx>,
+ impls_map: CrateInherentImpls,
+}
+
+impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for InherentCollect<'a, 'tcx> {
+ fn visit_item(&mut self, item: &hir::Item) {
+ let (unsafety, ty) = match item.node {
+ hir::ItemImpl(unsafety, .., None, ref ty, _) => (unsafety, ty),
+ _ => return
+ };
+
+ match unsafety {
+ hir::Unsafety::Normal => {
+ // OK
+ }
+ hir::Unsafety::Unsafe => {
+ span_err!(self.tcx.sess,
+ item.span,
+ E0197,
+ "inherent impls cannot be declared as unsafe");
+ }
+ }
+
+ let def_id = self.tcx.hir.local_def_id(item.id);
+ let self_ty = self.tcx.item_type(def_id);
+ match self_ty.sty {
+ ty::TyAdt(def, _) => {
+ self.check_def_id(item, def.did);
+ }
+ ty::TyDynamic(ref data, ..) if data.principal().is_some() => {
+ self.check_def_id(item, data.principal().unwrap().def_id());
+ }
+ ty::TyChar => {
+ self.check_primitive_impl(def_id,
+ self.tcx.lang_items.char_impl(),
+ "char",
+ "char",
+ item.span);
+ }
+ ty::TyStr => {
+ self.check_primitive_impl(def_id,
+ self.tcx.lang_items.str_impl(),
+ "str",
+ "str",
+ item.span);
+ }
+ ty::TySlice(_) => {
+ self.check_primitive_impl(def_id,
+ self.tcx.lang_items.slice_impl(),
+ "slice",
+ "[T]",
+ item.span);
+ }
+ ty::TyRawPtr(ty::TypeAndMut { ty: _, mutbl: hir::MutImmutable }) => {
+ self.check_primitive_impl(def_id,
+ self.tcx.lang_items.const_ptr_impl(),
+ "const_ptr",
+ "*const T",
+ item.span);
+ }
+ ty::TyRawPtr(ty::TypeAndMut { ty: _, mutbl: hir::MutMutable }) => {
+ self.check_primitive_impl(def_id,
+ self.tcx.lang_items.mut_ptr_impl(),
+ "mut_ptr",
+ "*mut T",
+ item.span);
+ }
+ ty::TyInt(ast::IntTy::I8) => {
+ self.check_primitive_impl(def_id,
+ self.tcx.lang_items.i8_impl(),
+ "i8",
+ "i8",
+ item.span);
+ }
+ ty::TyInt(ast::IntTy::I16) => {
+ self.check_primitive_impl(def_id,
+ self.tcx.lang_items.i16_impl(),
+ "i16",
+ "i16",
+ item.span);
+ }
+ ty::TyInt(ast::IntTy::I32) => {
+ self.check_primitive_impl(def_id,
+ self.tcx.lang_items.i32_impl(),
+ "i32",
+ "i32",
+ item.span);
+ }
+ ty::TyInt(ast::IntTy::I64) => {
+ self.check_primitive_impl(def_id,
+ self.tcx.lang_items.i64_impl(),
+ "i64",
+ "i64",
+ item.span);
+ }
+ ty::TyInt(ast::IntTy::I128) => {
+ self.check_primitive_impl(def_id,
+ self.tcx.lang_items.i128_impl(),
+ "i128",
+ "i128",
+ item.span);
+ }
+ ty::TyInt(ast::IntTy::Is) => {
+ self.check_primitive_impl(def_id,
+ self.tcx.lang_items.isize_impl(),
+ "isize",
+ "isize",
+ item.span);
+ }
+ ty::TyUint(ast::UintTy::U8) => {
+ self.check_primitive_impl(def_id,
+ self.tcx.lang_items.u8_impl(),
+ "u8",
+ "u8",
+ item.span);
+ }
+ ty::TyUint(ast::UintTy::U16) => {
+ self.check_primitive_impl(def_id,
+ self.tcx.lang_items.u16_impl(),
+ "u16",
+ "u16",
+ item.span);
+ }
+ ty::TyUint(ast::UintTy::U32) => {
+ self.check_primitive_impl(def_id,
+ self.tcx.lang_items.u32_impl(),
+ "u32",
+ "u32",
+ item.span);
+ }
+ ty::TyUint(ast::UintTy::U64) => {
+ self.check_primitive_impl(def_id,
+ self.tcx.lang_items.u64_impl(),
+ "u64",
+ "u64",
+ item.span);
+ }
+ ty::TyUint(ast::UintTy::U128) => {
+ self.check_primitive_impl(def_id,
+ self.tcx.lang_items.u128_impl(),
+ "u128",
+ "u128",
+ item.span);
+ }
+ ty::TyUint(ast::UintTy::Us) => {
+ self.check_primitive_impl(def_id,
+ self.tcx.lang_items.usize_impl(),
+ "usize",
+ "usize",
+ item.span);
+ }
+ ty::TyFloat(ast::FloatTy::F32) => {
+ self.check_primitive_impl(def_id,
+ self.tcx.lang_items.f32_impl(),
+ "f32",
+ "f32",
+ item.span);
+ }
+ ty::TyFloat(ast::FloatTy::F64) => {
+ self.check_primitive_impl(def_id,
+ self.tcx.lang_items.f64_impl(),
+ "f64",
+ "f64",
+ item.span);
+ }
+ ty::TyError => {
+ return;
+ }
+ _ => {
+ struct_span_err!(self.tcx.sess,
+ ty.span,
+ E0118,
+ "no base type found for inherent implementation")
+ .span_label(ty.span, &format!("impl requires a base type"))
+ .note(&format!("either implement a trait on it or create a newtype \
+ to wrap it instead"))
+ .emit();
+ return;
+ }
+ }
+ }
+
+ fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem) {
+ }
+
+ fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) {
+ }
+}
+
+impl<'a, 'tcx> InherentCollect<'a, 'tcx> {
+ fn check_def_id(&mut self, item: &hir::Item, def_id: DefId) {
+ if def_id.is_local() {
+ // Add the implementation to the mapping from implementation to base
+ // type def ID, if there is a base type for this implementation and
+ // the implementation does not have any associated traits.
+ let impl_def_id = self.tcx.hir.local_def_id(item.id);
+ let mut rc_vec = self.impls_map.inherent_impls
+ .entry(def_id)
+ .or_insert_with(|| Rc::new(vec![]));
+
+ // At this point, there should not be any clones of the
+ // `Rc`, so we can still safely push into it in place:
+ Rc::get_mut(&mut rc_vec).unwrap().push(impl_def_id);
+ } else {
+ struct_span_err!(self.tcx.sess,
+ item.span,
+ E0116,
+ "cannot define inherent `impl` for a type outside of the crate \
+ where the type is defined")
+ .span_label(item.span,
+ &format!("impl for type defined outside of crate."))
+ .note("define and implement a trait or new type instead")
+ .emit();
+ }
+ }
+
+ fn check_primitive_impl(&self,
+ impl_def_id: DefId,
+ lang_def_id: Option<DefId>,
+ lang: &str,
+ ty: &str,
+ span: Span) {
+ match lang_def_id {
+ Some(lang_def_id) if lang_def_id == impl_def_id => {
+ // OK
+ }
+ _ => {
+ struct_span_err!(self.tcx.sess,
+ span,
+ E0390,
+ "only a single inherent implementation marked with `#[lang = \
+ \"{}\"]` is allowed for the `{}` primitive",
+ lang,
+ ty)
+ .span_help(span, "consider using a trait to implement these methods")
+ .emit();
+ }
+ }
+ }
+}
+
--- /dev/null
+// 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 rustc::hir::def_id::{CrateNum, DefId, LOCAL_CRATE};
+use rustc::hir;
+use rustc::hir::itemlikevisit::ItemLikeVisitor;
+use rustc::lint;
+use rustc::traits::{self, Reveal};
+use rustc::ty::{self, TyCtxt};
+
+use syntax_pos::DUMMY_SP;
+
+pub fn crate_inherent_impls_overlap_check<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+ crate_num: CrateNum) {
+ assert_eq!(crate_num, LOCAL_CRATE);
+ let krate = tcx.hir.krate();
+ krate.visit_all_item_likes(&mut InherentOverlapChecker { tcx });
+}
+
+struct InherentOverlapChecker<'a, 'tcx: 'a> {
+ tcx: TyCtxt<'a, 'tcx, 'tcx>
+}
+
+impl<'a, 'tcx> InherentOverlapChecker<'a, 'tcx> {
+ fn check_for_common_items_in_impls(&self, impl1: DefId, impl2: DefId) {
+ #[derive(Copy, Clone, PartialEq)]
+ enum Namespace {
+ Type,
+ Value,
+ }
+
+ let name_and_namespace = |def_id| {
+ let item = self.tcx.associated_item(def_id);
+ (item.name, match item.kind {
+ ty::AssociatedKind::Type => Namespace::Type,
+ ty::AssociatedKind::Const |
+ ty::AssociatedKind::Method => Namespace::Value,
+ })
+ };
+
+ let impl_items1 = self.tcx.associated_item_def_ids(impl1);
+ let impl_items2 = self.tcx.associated_item_def_ids(impl2);
+
+ for &item1 in &impl_items1[..] {
+ let (name, namespace) = name_and_namespace(item1);
+
+ for &item2 in &impl_items2[..] {
+ if (name, namespace) == name_and_namespace(item2) {
+ let msg = format!("duplicate definitions with name `{}`", name);
+ let node_id = self.tcx.hir.as_local_node_id(item1).unwrap();
+ self.tcx.sess.add_lint(lint::builtin::OVERLAPPING_INHERENT_IMPLS,
+ node_id,
+ self.tcx.span_of_impl(item1).unwrap(),
+ msg);
+ }
+ }
+ }
+ }
+
+ fn check_for_overlapping_inherent_impls(&self, ty_def_id: DefId) {
+ let impls = ty::queries::inherent_impls::get(self.tcx, DUMMY_SP, ty_def_id);
+
+ for (i, &impl1_def_id) in impls.iter().enumerate() {
+ for &impl2_def_id in &impls[(i + 1)..] {
+ self.tcx.infer_ctxt((), Reveal::UserFacing).enter(|infcx| {
+ if traits::overlapping_impls(&infcx, impl1_def_id, impl2_def_id).is_some() {
+ self.check_for_common_items_in_impls(impl1_def_id, impl2_def_id)
+ }
+ });
+ }
+ }
+ }
+}
+
+impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for InherentOverlapChecker<'a, 'tcx> {
+ fn visit_item(&mut self, item: &'v hir::Item) {
+ match item.node {
+ hir::ItemEnum(..) |
+ hir::ItemStruct(..) |
+ hir::ItemTrait(..) |
+ hir::ItemUnion(..) => {
+ let type_def_id = self.tcx.hir.local_def_id(item.id);
+ self.check_for_overlapping_inherent_impls(type_def_id);
+ }
+ _ => {}
+ }
+ }
+
+ fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem) {
+ }
+
+ fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) {
+ }
+}
+
use syntax_pos::DUMMY_SP;
mod builtin;
-mod inherent;
+mod inherent_impls;
+mod inherent_impls_overlap;
mod orphan;
mod overlap;
mod unsafety;
pub fn provide(providers: &mut Providers) {
use self::builtin::coerce_unsized_info;
+ use self::inherent_impls::{crate_inherent_impls, inherent_impls};
+ use self::inherent_impls_overlap::crate_inherent_impls_overlap_check;
*providers = Providers {
coherent_trait,
- coherent_inherent_impls,
+ crate_inherent_impls,
+ inherent_impls,
+ crate_inherent_impls_overlap_check,
coerce_unsized_info,
..*providers
};
builtin::check_trait(tcx, def_id);
}
-fn coherent_inherent_impls<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, _: CrateNum) {
- inherent::check(tcx);
-}
-
pub fn check_coherence<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
let _task = tcx.dep_graph.in_task(DepNode::Coherence);
for &trait_def_id in tcx.hir.krate().trait_impls.keys() {
orphan::check(tcx);
overlap::check_default_impls(tcx);
- ty::queries::coherent_inherent_impls::get(tcx, DUMMY_SP, LOCAL_CRATE);
+ // these queries are executed for side-effects (error reporting):
+ ty::queries::crate_inherent_impls::get(tcx, DUMMY_SP, LOCAL_CRATE);
+ ty::queries::crate_inherent_impls_overlap_check::get(tcx, DUMMY_SP, LOCAL_CRATE);
}
pub fn build_impls(cx: &DocContext, did: DefId) -> Vec<clean::Item> {
let tcx = cx.tcx;
- tcx.populate_inherent_implementations_for_type_if_necessary(DUMMY_SP, did);
let mut impls = Vec::new();
- if let Some(i) = tcx.maps.inherent_impls.borrow().get(&did) {
- for &did in i.iter() {
- build_impl(cx, did, &mut impls);
- }
+ for &did in ty::queries::inherent_impls::get(tcx, DUMMY_SP, did).iter() {
+ build_impl(cx, did, &mut impls);
}
+
// If this is the first time we've inlined something from another crate, then
// we inline *all* impls from all the crates into this crate. Note that there's
// currently no way for us to filter this based on type, and we likely need