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