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.
16 use syntax
::ast
::{Item, ItemImpl}
;
19 use syntax
::codemap
::Span
;
22 pub fn check(tcx
: &ty
::ctxt
) {
23 let mut orphan
= OrphanChecker { tcx: tcx }
;
24 visit
::walk_crate(&mut orphan
, tcx
.map
.krate());
27 struct OrphanChecker
<'cx
, 'tcx
:'cx
> {
28 tcx
: &'cx ty
::ctxt
<'tcx
>
31 impl<'cx
, 'tcx
> OrphanChecker
<'cx
, 'tcx
> {
32 fn check_def_id(&self, item
: &ast
::Item
, def_id
: ast
::DefId
) {
33 if def_id
.krate
!= ast
::LOCAL_CRATE
{
34 span_err
!(self.tcx
.sess
, item
.span
, E0116
,
35 "cannot define inherent `impl` for a type outside of the \
36 crate where the type is defined; define and implement \
37 a trait or new type instead");
41 fn check_primitive_impl(&self,
42 impl_def_id
: ast
::DefId
,
43 lang_def_id
: Option
<ast
::DefId
>,
48 Some(lang_def_id
) if lang_def_id
== impl_def_id
=> { /* OK */ }
,
50 span_err
!(self.tcx
.sess
, span
, E0390
,
51 "only a single inherent implementation marked with `#[lang = \"{}\"]` \
52 is allowed for the `{}` primitive", lang
, ty
);
57 /// Checks exactly one impl for orphan rules and other such
58 /// restrictions. In this fn, it can happen that multiple errors
59 /// apply to a specific impl, so just return after reporting one
60 /// to prevent inundating the user with a bunch of similar error
62 fn check_item(&self, item
: &ast
::Item
) {
63 let def_id
= ast_util
::local_def(item
.id
);
65 ast
::ItemImpl(_
, _
, _
, None
, _
, _
) => {
66 // For inherent impls, self type must be a nominal type
67 // defined in this crate.
68 debug
!("coherence2::orphan check: inherent impl {}",
69 self.tcx
.map
.node_to_string(item
.id
));
70 let self_ty
= ty
::lookup_item_type(self.tcx
, def_id
).ty
;
72 ty
::TyEnum(def_id
, _
) |
73 ty
::TyStruct(def_id
, _
) => {
74 self.check_def_id(item
, def_id
);
76 ty
::TyTrait(ref data
) => {
77 self.check_def_id(item
, data
.principal_def_id());
80 self.check_def_id(item
, self.tcx
.lang_items
.owned_box().unwrap());
83 self.check_primitive_impl(def_id
,
84 self.tcx
.lang_items
.char_impl(),
90 self.check_primitive_impl(def_id
,
91 self.tcx
.lang_items
.str_impl(),
97 self.check_primitive_impl(def_id
,
98 self.tcx
.lang_items
.slice_impl(),
103 ty
::TyRawPtr(ty
::mt { ty: _, mutbl: ast::MutImmutable }
) => {
104 self.check_primitive_impl(def_id
,
105 self.tcx
.lang_items
.const_ptr_impl(),
110 ty
::TyRawPtr(ty
::mt { ty: _, mutbl: ast::MutMutable }
) => {
111 self.check_primitive_impl(def_id
,
112 self.tcx
.lang_items
.mut_ptr_impl(),
117 ty
::TyInt(ast
::TyI8
) => {
118 self.check_primitive_impl(def_id
,
119 self.tcx
.lang_items
.i8_impl(),
124 ty
::TyInt(ast
::TyI16
) => {
125 self.check_primitive_impl(def_id
,
126 self.tcx
.lang_items
.i16_impl(),
131 ty
::TyInt(ast
::TyI32
) => {
132 self.check_primitive_impl(def_id
,
133 self.tcx
.lang_items
.i32_impl(),
138 ty
::TyInt(ast
::TyI64
) => {
139 self.check_primitive_impl(def_id
,
140 self.tcx
.lang_items
.i64_impl(),
145 ty
::TyInt(ast
::TyIs
) => {
146 self.check_primitive_impl(def_id
,
147 self.tcx
.lang_items
.isize_impl(),
152 ty
::TyUint(ast
::TyU8
) => {
153 self.check_primitive_impl(def_id
,
154 self.tcx
.lang_items
.u8_impl(),
159 ty
::TyUint(ast
::TyU16
) => {
160 self.check_primitive_impl(def_id
,
161 self.tcx
.lang_items
.u16_impl(),
166 ty
::TyUint(ast
::TyU32
) => {
167 self.check_primitive_impl(def_id
,
168 self.tcx
.lang_items
.u32_impl(),
173 ty
::TyUint(ast
::TyU64
) => {
174 self.check_primitive_impl(def_id
,
175 self.tcx
.lang_items
.u64_impl(),
180 ty
::TyUint(ast
::TyUs
) => {
181 self.check_primitive_impl(def_id
,
182 self.tcx
.lang_items
.usize_impl(),
187 ty
::TyFloat(ast
::TyF32
) => {
188 self.check_primitive_impl(def_id
,
189 self.tcx
.lang_items
.f32_impl(),
194 ty
::TyFloat(ast
::TyF64
) => {
195 self.check_primitive_impl(def_id
,
196 self.tcx
.lang_items
.f64_impl(),
202 span_err
!(self.tcx
.sess
, item
.span
, E0118
,
203 "no base type found for inherent implementation; \
204 implement a trait or new type instead");
209 ast
::ItemImpl(_
, _
, _
, Some(_
), _
, _
) => {
211 debug
!("coherence2::orphan check: trait impl {}",
212 self.tcx
.map
.node_to_string(item
.id
));
213 let trait_ref
= ty
::impl_trait_ref(self.tcx
, def_id
).unwrap();
214 let trait_def_id
= trait_ref
.def_id
;
215 match traits
::orphan_check(self.tcx
, def_id
) {
217 Err(traits
::OrphanCheckErr
::NoLocalInputType
) => {
219 self.tcx
.sess
, item
.span
, E0117
,
220 "the impl does not reference any \
221 types defined in this crate; \
222 only traits defined in the current crate can be \
223 implemented for arbitrary types");
226 Err(traits
::OrphanCheckErr
::UncoveredTy(param_ty
)) => {
227 span_err
!(self.tcx
.sess
, item
.span
, E0210
,
228 "type parameter `{}` must be used as the type parameter for \
229 some local type (e.g. `MyStruct<T>`); only traits defined in \
230 the current crate can be implemented for a type parameter",
236 // In addition to the above rules, we restrict impls of defaulted traits
237 // so that they can only be implemented on structs/enums. To see why this
238 // restriction exists, consider the following example (#22978). Imagine
239 // that crate A defines a defaulted trait `Foo` and a fn that operates
240 // on pairs of types:
245 // impl Foo for .. { }
246 // fn two_foos<A:Foo,B:Foo>(..) {
247 // one_foo::<(A,B)>(..)
249 // fn one_foo<T:Foo>(..) { .. }
252 // This type-checks fine; in particular the fn
253 // `two_foos` is able to conclude that `(A,B):Foo`
254 // because `A:Foo` and `B:Foo`.
256 // Now imagine that crate B comes along and does the following:
261 // impl Foo for A { }
262 // impl Foo for B { }
263 // impl !Send for (A, B) { }
266 // This final impl is legal according to the orpan
267 // rules, but it invalidates the reasoning from
269 debug
!("trait_ref={:?} trait_def_id={:?} trait_has_default_impl={}",
272 ty
::trait_has_default_impl(self.tcx
, trait_def_id
));
274 ty
::trait_has_default_impl(self.tcx
, trait_def_id
) &&
275 trait_def_id
.krate
!= ast
::LOCAL_CRATE
277 let self_ty
= trait_ref
.self_ty();
278 let opt_self_def_id
= match self_ty
.sty
{
279 ty
::TyStruct(self_def_id
, _
) | ty
::TyEnum(self_def_id
, _
) =>
282 self.tcx
.lang_items
.owned_box(),
287 let msg
= match opt_self_def_id
{
288 // We only want to permit structs/enums, but not *all* structs/enums.
289 // They must be local to the current crate, so that people
290 // can't do `unsafe impl Send for Rc<SomethingLocal>` or
291 // `impl !Send for Box<SomethingLocalAndSend>`.
292 Some(self_def_id
) => {
293 if self_def_id
.krate
== ast
::LOCAL_CRATE
{
297 "cross-crate traits with a default impl, like `{}`, \
298 can only be implemented for a struct/enum type \
299 defined in the current crate",
300 ty
::item_path_str(self.tcx
, trait_def_id
)))
305 "cross-crate traits with a default impl, like `{}`, \
306 can only be implemented for a struct/enum type, \
308 ty
::item_path_str(self.tcx
, trait_def_id
),
313 if let Some(msg
) = msg
{
314 span_err
!(self.tcx
.sess
, item
.span
, E0321
, "{}", msg
);
319 // Disallow *all* explicit impls of `Sized` and `Unsize` for now.
320 if Some(trait_def_id
) == self.tcx
.lang_items
.sized_trait() {
321 span_err
!(self.tcx
.sess
, item
.span
, E0322
,
322 "explicit impls for the `Sized` trait are not permitted");
325 if Some(trait_def_id
) == self.tcx
.lang_items
.unsize_trait() {
326 span_err
!(self.tcx
.sess
, item
.span
, E0328
,
327 "explicit impls for the `Unsize` trait are not permitted");
331 ast
::ItemDefaultImpl(..) => {
333 debug
!("coherence2::orphan check: default trait impl {}",
334 self.tcx
.map
.node_to_string(item
.id
));
335 let trait_ref
= ty
::impl_trait_ref(self.tcx
, def_id
).unwrap();
336 if trait_ref
.def_id
.krate
!= ast
::LOCAL_CRATE
{
337 span_err
!(self.tcx
.sess
, item
.span
, E0318
,
338 "cannot create default implementations for traits outside the \
339 crate they're defined in; define a new trait instead");
350 impl<'cx
, 'tcx
,'v
> visit
::Visitor
<'v
> for OrphanChecker
<'cx
, 'tcx
> {
351 fn visit_item(&mut self, item
: &ast
::Item
) {
352 self.check_item(item
);
353 visit
::walk_item(self, item
);