]> git.lizzy.rs Git - rust.git/blob - src/librustc_typeck/coherence/overlap.rs
Update E0253.rs
[rust.git] / src / librustc_typeck / coherence / overlap.rs
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.
4 //
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.
10
11 //! Overlap: No two impls for the same trait are implemented for the
12 //! same type. Likewise, no two inherent impls for a given type
13 //! constructor provide a method with the same name.
14
15 use hir::def_id::DefId;
16 use rustc::traits::{self, ProjectionMode};
17 use rustc::ty::{self, TyCtxt};
18 use syntax::ast;
19 use rustc::dep_graph::DepNode;
20 use rustc::hir;
21 use rustc::hir::intravisit;
22 use util::nodemap::DefIdMap;
23 use lint;
24
25 pub fn check<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
26     let mut overlap = OverlapChecker { tcx: tcx,
27                                        default_impls: DefIdMap() };
28
29     // this secondary walk specifically checks for some other cases,
30     // like defaulted traits, for which additional overlap rules exist
31     tcx.visit_all_items_in_krate(DepNode::CoherenceOverlapCheckSpecial, &mut overlap);
32 }
33
34 struct OverlapChecker<'cx, 'tcx:'cx> {
35     tcx: TyCtxt<'cx, 'tcx, 'tcx>,
36
37     // maps from a trait def-id to an impl id
38     default_impls: DefIdMap<ast::NodeId>,
39 }
40
41 impl<'cx, 'tcx> OverlapChecker<'cx, 'tcx> {
42     fn check_for_common_items_in_impls(&self, impl1: DefId, impl2: DefId) {
43         #[derive(Copy, Clone, PartialEq)]
44         enum Namespace { Type, Value }
45
46         fn name_and_namespace<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
47                                         item: &ty::ImplOrTraitItemId)
48                                         -> (ast::Name, Namespace)
49         {
50             let name = tcx.impl_or_trait_item(item.def_id()).name();
51             (name, match *item {
52                 ty::TypeTraitItemId(..) => Namespace::Type,
53                 ty::ConstTraitItemId(..) => Namespace::Value,
54                 ty::MethodTraitItemId(..) => Namespace::Value,
55             })
56         }
57
58         let impl_items = self.tcx.impl_items.borrow();
59
60         for item1 in &impl_items[&impl1] {
61             let (name, namespace) = name_and_namespace(self.tcx, item1);
62
63             for item2 in &impl_items[&impl2] {
64                 if (name, namespace) == name_and_namespace(self.tcx, item2) {
65                     let msg = format!("duplicate definitions with name `{}`", name);
66                     let node_id = self.tcx.map.as_local_node_id(item1.def_id()).unwrap();
67                     self.tcx.sess.add_lint(lint::builtin::OVERLAPPING_INHERENT_IMPLS,
68                                            node_id,
69                                            self.tcx.span_of_impl(item1.def_id()).unwrap(),
70                                            msg);
71                 }
72             }
73         }
74     }
75
76     fn check_for_overlapping_inherent_impls(&self, ty_def_id: DefId) {
77         let _task = self.tcx.dep_graph.in_task(DepNode::CoherenceOverlapInherentCheck(ty_def_id));
78
79         let inherent_impls = self.tcx.inherent_impls.borrow();
80         let impls = match inherent_impls.get(&ty_def_id) {
81             Some(impls) => impls,
82             None => return
83         };
84
85         for (i, &impl1_def_id) in impls.iter().enumerate() {
86             for &impl2_def_id in &impls[(i+1)..] {
87                 self.tcx.infer_ctxt(None, None, ProjectionMode::Topmost).enter(|infcx| {
88                     if traits::overlapping_impls(&infcx, impl1_def_id, impl2_def_id).is_some() {
89                         self.check_for_common_items_in_impls(impl1_def_id, impl2_def_id)
90                     }
91                 });
92             }
93         }
94     }
95 }
96
97 impl<'cx, 'tcx,'v> intravisit::Visitor<'v> for OverlapChecker<'cx, 'tcx> {
98     fn visit_item(&mut self, item: &'v hir::Item) {
99         match item.node {
100             hir::ItemEnum(..) | hir::ItemStruct(..) => {
101                 let type_def_id = self.tcx.map.local_def_id(item.id);
102                 self.check_for_overlapping_inherent_impls(type_def_id);
103             }
104
105             hir::ItemDefaultImpl(..) => {
106                 // look for another default impl; note that due to the
107                 // general orphan/coherence rules, it must always be
108                 // in this crate.
109                 let impl_def_id = self.tcx.map.local_def_id(item.id);
110                 let trait_ref = self.tcx.impl_trait_ref(impl_def_id).unwrap();
111
112                 let prev_default_impl = self.default_impls.insert(trait_ref.def_id, item.id);
113                 if let Some(prev_id) = prev_default_impl {
114                     let mut err = struct_span_err!(
115                         self.tcx.sess,
116                         self.tcx.span_of_impl(impl_def_id).unwrap(), E0521,
117                         "redundant default implementations of trait `{}`:",
118                         trait_ref);
119                     err.span_note(self.tcx.span_of_impl(self.tcx.map.local_def_id(prev_id))
120                                       .unwrap(),
121                                   "redundant implementation is here:");
122                     err.emit();
123                 }
124             }
125             hir::ItemImpl(_, _, _, Some(_), _, _) => {
126                 let impl_def_id = self.tcx.map.local_def_id(item.id);
127                 let trait_ref = self.tcx.impl_trait_ref(impl_def_id).unwrap();
128                 let trait_def_id = trait_ref.def_id;
129
130                 let _task = self.tcx.dep_graph.in_task(
131                     DepNode::CoherenceOverlapCheck(trait_def_id));
132
133                 let def = self.tcx.lookup_trait_def(trait_def_id);
134
135                 // attempt to insert into the specialization graph
136                 let insert_result = def.add_impl_for_specialization(self.tcx, impl_def_id);
137
138                 // insertion failed due to overlap
139                 if let Err(overlap) = insert_result {
140                     let mut err = struct_span_err!(
141                         self.tcx.sess, self.tcx.span_of_impl(impl_def_id).unwrap(), E0119,
142                         "conflicting implementations of trait `{}`{}:",
143                         overlap.trait_desc,
144                         overlap.self_desc.clone().map_or(String::new(),
145                                                          |ty| format!(" for type `{}`", ty)));
146
147                     match self.tcx.span_of_impl(overlap.with_impl) {
148                         Ok(span) => {
149                             err.span_label(span,
150                                            &format!("first implementation here"));
151                             err.span_label(self.tcx.span_of_impl(impl_def_id).unwrap(),
152                                            &format!("conflicting implementation{}",
153                                                     overlap.self_desc
154                                                         .map_or(String::new(),
155                                                                 |ty| format!(" for `{}`", ty))));
156                         }
157                         Err(cname) => {
158                             err.note(&format!("conflicting implementation in crate `{}`",
159                                               cname));
160                         }
161                     }
162
163                     err.emit();
164                 }
165
166                 // check for overlap with the automatic `impl Trait for Trait`
167                 if let ty::TyTrait(ref data) = trait_ref.self_ty().sty {
168                     // This is something like impl Trait1 for Trait2. Illegal
169                     // if Trait1 is a supertrait of Trait2 or Trait2 is not object safe.
170
171                     if !self.tcx.is_object_safe(data.principal_def_id()) {
172                         // This is an error, but it will be
173                         // reported by wfcheck.  Ignore it
174                         // here. This is tested by
175                         // `coherence-impl-trait-for-trait-object-safe.rs`.
176                     } else {
177                         let mut supertrait_def_ids =
178                             traits::supertrait_def_ids(self.tcx, data.principal_def_id());
179                         if supertrait_def_ids.any(|d| d == trait_def_id) {
180                             span_err!(self.tcx.sess, item.span, E0371,
181                                       "the object type `{}` automatically \
182                                        implements the trait `{}`",
183                                       trait_ref.self_ty(),
184                                       self.tcx.item_path_str(trait_def_id));
185                         }
186                     }
187                 }
188             }
189             _ => {}
190         }
191     }
192 }