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