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.
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.
11 //! Orphan checker: every impl either implements a trait defined in this
12 //! crate or pertains to a type defined in this crate.
15 use rustc
::ty
::{self, TyCtxt}
;
16 use rustc
::hir
::itemlikevisit
::ItemLikeVisitor
;
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
);
24 struct OrphanChecker
<'cx
, 'tcx
: 'cx
> {
25 tcx
: TyCtxt
<'cx
, 'tcx
, 'tcx
>,
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
34 fn visit_item(&mut self, item
: &hir
::Item
) {
35 let def_id
= self.tcx
.hir
.local_def_id(item
.id
);
37 hir
::ItemImpl(.., Some(_
), _
, _
) => {
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
) {
45 Err(traits
::OrphanCheckErr
::NoLocalInputType
) => {
46 struct_span_err
!(self.tcx
.sess
,
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 \
54 .note("define and implement a trait or new type instead")
58 Err(traits
::OrphanCheckErr
::UncoveredTy(param_ty
)) => {
59 span_err
!(self.tcx
.sess
,
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",
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:
79 // impl Foo for .. { }
80 // fn two_foos<A:Foo,B:Foo>(..) {
81 // one_foo::<(A,B)>(..)
83 // fn one_foo<T:Foo>(..) { .. }
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`.
90 // Now imagine that crate B comes along and does the following:
97 // impl !Send for (A, B) { }
100 // This final impl is legal according to the orpan
101 // rules, but it invalidates the reasoning from
103 debug
!("trait_ref={:?} trait_def_id={:?} trait_is_auto={}",
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
),
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() {
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
)))
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
),
139 if let Some(msg
) = msg
{
140 span_err
!(self.tcx
.sess
, item
.span
, E0321
, "{}", msg
);
145 hir
::ItemAutoImpl(_
, ref item_trait_ref
) => {
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
,
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
)))
169 fn visit_trait_item(&mut self, _trait_item
: &hir
::TraitItem
) {
172 fn visit_impl_item(&mut self, _impl_item
: &hir
::ImplItem
) {