]> git.lizzy.rs Git - rust.git/blob - src/librustc_typeck/coherence/orphan.rs
Auto merge of #45013 - chrisvittal:mir_pretty_printing_pr, r=nikomatsakis
[rust.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 structs/enums. To see why this
72                 // restriction exists, consider the following example (#22978). Imagine
73                 // that crate A defines a defaulted trait `Foo` and a fn that operates
74                 // 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_has_default_impl={}",
104                        trait_ref,
105                        trait_def_id,
106                        self.tcx.trait_has_default_impl(trait_def_id));
107                 if self.tcx.trait_has_default_impl(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                         _ => None,
113                     };
114
115                     let msg = match opt_self_def_id {
116                         // We only want to permit structs/enums, but not *all* structs/enums.
117                         // They must be local to the current crate, so that people
118                         // can't do `unsafe impl Send for Rc<SomethingLocal>` or
119                         // `impl !Send for Box<SomethingLocalAndSend>`.
120                         Some(self_def_id) => {
121                             if self_def_id.is_local() {
122                                 None
123                             } else {
124                                 Some(format!("cross-crate traits with a default impl, like `{}`, \
125                                               can only be implemented for a struct/enum type \
126                                               defined in the current crate",
127                                              self.tcx.item_path_str(trait_def_id)))
128                             }
129                         }
130                         _ => {
131                             Some(format!("cross-crate traits with a default impl, like `{}`, can \
132                                           only be implemented for a struct/enum type, not `{}`",
133                                          self.tcx.item_path_str(trait_def_id),
134                                          self_ty))
135                         }
136                     };
137
138                     if let Some(msg) = msg {
139                         span_err!(self.tcx.sess, item.span, E0321, "{}", msg);
140                         return;
141                     }
142                 }
143             }
144             hir::ItemDefaultImpl(_, ref item_trait_ref) => {
145                 // "Trait" impl
146                 debug!("coherence2::orphan check: default trait impl {}",
147                        self.tcx.hir.node_to_string(item.id));
148                 let trait_ref = self.tcx.impl_trait_ref(def_id).unwrap();
149                 if !trait_ref.def_id.is_local() {
150                     struct_span_err!(self.tcx.sess,
151                                      item_trait_ref.path.span,
152                                      E0318,
153                                      "cannot create default implementations for traits outside \
154                                       the crate they're defined in; define a new trait instead")
155                         .span_label(item_trait_ref.path.span,
156                                     format!("`{}` trait not defined in this crate",
157                             self.tcx.hir.node_to_pretty_string(item_trait_ref.ref_id)))
158                         .emit();
159                     return;
160                 }
161             }
162             _ => {
163                 // Not an impl
164             }
165         }
166     }
167
168     fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem) {
169     }
170
171     fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) {
172     }
173 }