]> git.proxmox.com Git - rustc.git/blob - src/librustc_typeck/coherence/orphan.rs
New upstream version 1.23.0+dfsg1
[rustc.git] / src / librustc_typeck / coherence / orphan.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 //! Orphan checker: every impl either implements a trait defined in this
12 //! crate or pertains to a type defined in this crate.
13
14 use rustc::traits;
15 use rustc::ty::{self, TyCtxt};
16 use rustc::hir::itemlikevisit::ItemLikeVisitor;
17 use rustc::hir;
18
19 pub fn check<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
20 let mut orphan = OrphanChecker { tcx: tcx };
21 tcx.hir.krate().visit_all_item_likes(&mut orphan);
22 }
23
24 struct OrphanChecker<'cx, 'tcx: 'cx> {
25 tcx: TyCtxt<'cx, 'tcx, 'tcx>,
26 }
27
28 impl<'cx, 'tcx, 'v> ItemLikeVisitor<'v> for OrphanChecker<'cx, 'tcx> {
29 /// Checks exactly one impl for orphan rules and other such
30 /// restrictions. In this fn, it can happen that multiple errors
31 /// apply to a specific impl, so just return after reporting one
32 /// to prevent inundating the user with a bunch of similar error
33 /// reports.
34 fn visit_item(&mut self, item: &hir::Item) {
35 let def_id = self.tcx.hir.local_def_id(item.id);
36 match item.node {
37 hir::ItemImpl(.., Some(_), _, _) => {
38 // "Trait" impl
39 debug!("coherence2::orphan check: trait impl {}",
40 self.tcx.hir.node_to_string(item.id));
41 let trait_ref = self.tcx.impl_trait_ref(def_id).unwrap();
42 let trait_def_id = trait_ref.def_id;
43 match traits::orphan_check(self.tcx, def_id) {
44 Ok(()) => {}
45 Err(traits::OrphanCheckErr::NoLocalInputType) => {
46 struct_span_err!(self.tcx.sess,
47 item.span,
48 E0117,
49 "only traits defined in the current crate can be \
50 implemented for arbitrary types")
51 .span_label(item.span, "impl doesn't use types inside crate")
52 .note(&format!("the impl does not reference any types defined in \
53 this crate"))
54 .note("define and implement a trait or new type instead")
55 .emit();
56 return;
57 }
58 Err(traits::OrphanCheckErr::UncoveredTy(param_ty)) => {
59 span_err!(self.tcx.sess,
60 item.span,
61 E0210,
62 "type parameter `{}` must be used as the type parameter for \
63 some local type (e.g. `MyStruct<T>`); only traits defined in \
64 the current crate can be implemented for a type parameter",
65 param_ty);
66 return;
67 }
68 }
69
70 // In addition to the above rules, we restrict impls of defaulted traits
71 // so that they can only be implemented on nominal types, such as structs,
72 // enums or foreign types. To see why this restriction exists, consider the
73 // following example (#22978). Imagine that crate A defines a defaulted trait
74 // `Foo` and a fn that operates on pairs of types:
75 //
76 // ```
77 // // Crate A
78 // trait Foo { }
79 // impl Foo for .. { }
80 // fn two_foos<A:Foo,B:Foo>(..) {
81 // one_foo::<(A,B)>(..)
82 // }
83 // fn one_foo<T:Foo>(..) { .. }
84 // ```
85 //
86 // This type-checks fine; in particular the fn
87 // `two_foos` is able to conclude that `(A,B):Foo`
88 // because `A:Foo` and `B:Foo`.
89 //
90 // Now imagine that crate B comes along and does the following:
91 //
92 // ```
93 // struct A { }
94 // struct B { }
95 // impl Foo for A { }
96 // impl Foo for B { }
97 // impl !Send for (A, B) { }
98 // ```
99 //
100 // This final impl is legal according to the orpan
101 // rules, but it invalidates the reasoning from
102 // `two_foos` above.
103 debug!("trait_ref={:?} trait_def_id={:?} trait_is_auto={}",
104 trait_ref,
105 trait_def_id,
106 self.tcx.trait_is_auto(trait_def_id));
107 if self.tcx.trait_is_auto(trait_def_id) &&
108 !trait_def_id.is_local() {
109 let self_ty = trait_ref.self_ty();
110 let opt_self_def_id = match self_ty.sty {
111 ty::TyAdt(self_def, _) => Some(self_def.did),
112 ty::TyForeign(did) => Some(did),
113 _ => None,
114 };
115
116 let msg = match opt_self_def_id {
117 // We only want to permit nominal types, but not *all* nominal types.
118 // They must be local to the current crate, so that people
119 // can't do `unsafe impl Send for Rc<SomethingLocal>` or
120 // `impl !Send for Box<SomethingLocalAndSend>`.
121 Some(self_def_id) => {
122 if self_def_id.is_local() {
123 None
124 } else {
125 Some(format!("cross-crate traits with a default impl, like `{}`, \
126 can only be implemented for a struct/enum type \
127 defined in the current crate",
128 self.tcx.item_path_str(trait_def_id)))
129 }
130 }
131 _ => {
132 Some(format!("cross-crate traits with a default impl, like `{}`, can \
133 only be implemented for a struct/enum type, not `{}`",
134 self.tcx.item_path_str(trait_def_id),
135 self_ty))
136 }
137 };
138
139 if let Some(msg) = msg {
140 span_err!(self.tcx.sess, item.span, E0321, "{}", msg);
141 return;
142 }
143 }
144 }
145 hir::ItemAutoImpl(_, ref item_trait_ref) => {
146 // "Trait" impl
147 debug!("coherence2::orphan check: default trait impl {}",
148 self.tcx.hir.node_to_string(item.id));
149 let trait_ref = self.tcx.impl_trait_ref(def_id).unwrap();
150 if !trait_ref.def_id.is_local() {
151 struct_span_err!(self.tcx.sess,
152 item_trait_ref.path.span,
153 E0318,
154 "cannot create default implementations for traits outside \
155 the crate they're defined in; define a new trait instead")
156 .span_label(item_trait_ref.path.span,
157 format!("`{}` trait not defined in this crate",
158 self.tcx.hir.node_to_pretty_string(item_trait_ref.ref_id)))
159 .emit();
160 return;
161 }
162 }
163 _ => {
164 // Not an impl
165 }
166 }
167 }
168
169 fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem) {
170 }
171
172 fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) {
173 }
174 }