1 // Copyright 2014 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
11 //! Overlap: No two impls for the same trait are implemented for the
16 use middle
::infer
::{self, new_infer_ctxt}
;
17 use syntax
::ast
::DefId
;
18 use syntax
::ast
::LOCAL_CRATE
;
22 use syntax
::codemap
::Span
;
23 use util
::nodemap
::DefIdMap
;
24 use util
::ppaux
::Repr
;
26 pub fn check(tcx
: &ty
::ctxt
) {
27 let mut overlap
= OverlapChecker { tcx: tcx, default_impls: DefIdMap() }
;
28 overlap
.check_for_overlapping_impls();
30 // this secondary walk specifically checks for impls of defaulted
31 // traits, for which additional overlap rules exist
32 visit
::walk_crate(&mut overlap
, tcx
.map
.krate());
35 struct OverlapChecker
<'cx
, 'tcx
:'cx
> {
36 tcx
: &'cx ty
::ctxt
<'tcx
>,
38 // maps from a trait def-id to an impl id
39 default_impls
: DefIdMap
<ast
::NodeId
>,
42 impl<'cx
, 'tcx
> OverlapChecker
<'cx
, 'tcx
> {
43 fn check_for_overlapping_impls(&self) {
44 debug
!("check_for_overlapping_impls");
46 // Collect this into a vector to avoid holding the
47 // refcell-lock during the
48 // check_for_overlapping_impls_of_trait() check, since that
49 // check can populate this table further with impls from other
51 let trait_def_ids
: Vec
<(ast
::DefId
, Vec
<ast
::DefId
>)> =
52 self.tcx
.trait_impls
.borrow().iter().map(|(&k
, v
)| {
53 // FIXME -- it seems like this method actually pushes
54 // duplicate impls onto the list
55 ty
::populate_implementations_for_trait_if_necessary(self.tcx
, k
);
56 (k
, v
.borrow().clone())
59 for &(trait_def_id
, ref impls
) in &trait_def_ids
{
60 self.check_for_overlapping_impls_of_trait(trait_def_id
, impls
);
64 fn check_for_overlapping_impls_of_trait(&self,
65 trait_def_id
: ast
::DefId
,
66 trait_impls
: &Vec
<ast
::DefId
>)
68 debug
!("check_for_overlapping_impls_of_trait(trait_def_id={})",
69 trait_def_id
.repr(self.tcx
));
71 for (i
, &impl1_def_id
) in trait_impls
.iter().enumerate() {
72 if impl1_def_id
.krate
!= ast
::LOCAL_CRATE
{
73 // we don't need to check impls if both are external;
74 // that's the other crate's job.
78 for &impl2_def_id
in &trait_impls
[(i
+1)..] {
79 self.check_if_impls_overlap(trait_def_id
,
86 fn check_if_impls_overlap(&self,
87 trait_def_id
: ast
::DefId
,
88 impl1_def_id
: ast
::DefId
,
89 impl2_def_id
: ast
::DefId
)
91 assert_eq
!(impl1_def_id
.krate
, ast
::LOCAL_CRATE
);
93 debug
!("check_if_impls_overlap({}, {}, {})",
94 trait_def_id
.repr(self.tcx
),
95 impl1_def_id
.repr(self.tcx
),
96 impl2_def_id
.repr(self.tcx
));
98 let infcx
= infer
::new_infer_ctxt(self.tcx
);
99 if !traits
::overlapping_impls(&infcx
, impl1_def_id
, impl2_def_id
) {
103 self.report_overlap_error(trait_def_id
, impl1_def_id
, impl2_def_id
);
106 fn report_overlap_error(&self, trait_def_id
: ast
::DefId
,
107 impl1
: ast
::DefId
, impl2
: ast
::DefId
) {
109 span_err
!(self.tcx
.sess
, self.span_of_impl(impl1
), E0119
,
110 "conflicting implementations for trait `{}`",
111 ty
::item_path_str(self.tcx
, trait_def_id
));
113 self.report_overlap_note(impl1
, impl2
);
116 fn report_overlap_note(&self, impl1
: ast
::DefId
, impl2
: ast
::DefId
) {
118 if impl2
.krate
== ast
::LOCAL_CRATE
{
119 span_note
!(self.tcx
.sess
, self.span_of_impl(impl2
),
120 "note conflicting implementation here");
122 let crate_store
= &self.tcx
.sess
.cstore
;
123 let cdata
= crate_store
.get_crate_data(impl2
.krate
);
124 span_note
!(self.tcx
.sess
, self.span_of_impl(impl1
),
125 "conflicting implementation in crate `{}`",
130 fn span_of_impl(&self, impl_did
: ast
::DefId
) -> Span
{
131 assert_eq
!(impl_did
.krate
, ast
::LOCAL_CRATE
);
132 self.tcx
.map
.span(impl_did
.node
)
137 impl<'cx
, 'tcx
,'v
> visit
::Visitor
<'v
> for OverlapChecker
<'cx
, 'tcx
> {
138 fn visit_item(&mut self, item
: &'v ast
::Item
) {
140 ast
::ItemDefaultImpl(_
, _
) => {
141 // look for another default impl; note that due to the
142 // general orphan/coherence rules, it must always be
144 let impl_def_id
= ast_util
::local_def(item
.id
);
145 let trait_ref
= ty
::impl_trait_ref(self.tcx
, impl_def_id
).unwrap();
146 let prev_default_impl
= self.default_impls
.insert(trait_ref
.def_id
, item
.id
);
147 match prev_default_impl
{
149 self.report_overlap_error(trait_ref
.def_id
,
151 ast_util
::local_def(prev_id
));