]> git.lizzy.rs Git - rust.git/blob - src/librustc_typeck/coherence/mod.rs
Improve diagnostics for inaccessible constructors
[rust.git] / src / librustc_typeck / coherence / mod.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 // Coherence phase
12 //
13 // The job of the coherence phase of typechecking is to ensure that
14 // each trait has at most one implementation for each type. This is
15 // done by the orphan and overlap modules. Then we build up various
16 // mappings. That mapping code resides here.
17
18 use hir::def_id::DefId;
19 use rustc::ty::{self, TyCtxt, TypeFoldable};
20 use rustc::ty::{Ty, TyBool, TyChar, TyError};
21 use rustc::ty::{TyParam, TyRawPtr};
22 use rustc::ty::{TyRef, TyAdt, TyDynamic, TyNever, TyTuple};
23 use rustc::ty::{TyStr, TyArray, TySlice, TyFloat, TyInfer, TyInt};
24 use rustc::ty::{TyUint, TyClosure, TyBox, TyFnDef, TyFnPtr};
25 use rustc::ty::{TyProjection, TyAnon};
26 use CrateCtxt;
27 use syntax_pos::Span;
28 use rustc::dep_graph::DepNode;
29 use rustc::hir::itemlikevisit::ItemLikeVisitor;
30 use rustc::hir::{Item, ItemImpl};
31 use rustc::hir;
32
33 mod builtin;
34 mod orphan;
35 mod overlap;
36 mod unsafety;
37
38 struct CoherenceChecker<'a, 'tcx: 'a> {
39     tcx: TyCtxt<'a, 'tcx, 'tcx>,
40 }
41
42 impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for CoherenceChecker<'a, 'tcx> {
43     fn visit_item(&mut self, item: &Item) {
44         if let ItemImpl(..) = item.node {
45             self.check_implementation(item)
46         }
47     }
48
49     fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem) {
50     }
51
52     fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) {
53     }
54 }
55
56 impl<'a, 'tcx> CoherenceChecker<'a, 'tcx> {
57     // Returns the def ID of the base type, if there is one.
58     fn get_base_type_def_id(&self, span: Span, ty: Ty<'tcx>) -> Option<DefId> {
59         match ty.sty {
60             TyAdt(def, _) => Some(def.did),
61
62             TyDynamic(ref t, ..) => t.principal().map(|p| p.def_id()),
63
64             TyBox(_) => self.tcx.lang_items.owned_box(),
65
66             TyBool | TyChar | TyInt(..) | TyUint(..) | TyFloat(..) | TyStr | TyArray(..) |
67             TySlice(..) | TyFnDef(..) | TyFnPtr(_) | TyTuple(..) | TyParam(..) | TyError |
68             TyNever | TyRawPtr(_) | TyRef(..) | TyProjection(..) => None,
69
70             TyInfer(..) | TyClosure(..) | TyAnon(..) => {
71                 // `ty` comes from a user declaration so we should only expect types
72                 // that the user can type
73                 span_bug!(span,
74                           "coherence encountered unexpected type searching for base type: {}",
75                           ty);
76             }
77         }
78     }
79
80     fn check(&mut self) {
81         // Check implementations and traits. This populates the tables
82         // containing the inherent methods and extension methods. It also
83         // builds up the trait inheritance table.
84         self.tcx.visit_all_item_likes_in_krate(DepNode::CoherenceCheckImpl, self);
85     }
86
87     fn check_implementation(&self, item: &Item) {
88         let tcx = self.tcx;
89         let impl_did = tcx.hir.local_def_id(item.id);
90         let self_type = tcx.item_type(impl_did);
91
92         // If there are no traits, then this implementation must have a
93         // base type.
94
95         if let Some(trait_ref) = self.tcx.impl_trait_ref(impl_did) {
96             debug!("(checking implementation) adding impl for trait '{:?}', item '{}'",
97                    trait_ref,
98                    item.name);
99
100             // Skip impls where one of the self type is an error type.
101             // This occurs with e.g. resolve failures (#30589).
102             if trait_ref.references_error() {
103                 return;
104             }
105
106             enforce_trait_manually_implementable(self.tcx, item.span, trait_ref.def_id);
107             self.add_trait_impl(trait_ref, impl_did);
108         } else {
109             // Skip inherent impls where the self type is an error
110             // type. This occurs with e.g. resolve failures (#30589).
111             if self_type.references_error() {
112                 return;
113             }
114
115             // Add the implementation to the mapping from implementation to base
116             // type def ID, if there is a base type for this implementation and
117             // the implementation does not have any associated traits.
118             if let Some(base_def_id) = self.get_base_type_def_id(item.span, self_type) {
119                 self.add_inherent_impl(base_def_id, impl_did);
120             }
121         }
122     }
123
124     fn add_inherent_impl(&self, base_def_id: DefId, impl_def_id: DefId) {
125         self.tcx.inherent_impls.borrow_mut().push(base_def_id, impl_def_id);
126     }
127
128     fn add_trait_impl(&self, impl_trait_ref: ty::TraitRef<'tcx>, impl_def_id: DefId) {
129         debug!("add_trait_impl: impl_trait_ref={:?} impl_def_id={:?}",
130                impl_trait_ref,
131                impl_def_id);
132         let trait_def = self.tcx.lookup_trait_def(impl_trait_ref.def_id);
133         trait_def.record_local_impl(self.tcx, impl_def_id, impl_trait_ref);
134     }
135 }
136
137 fn enforce_trait_manually_implementable(tcx: TyCtxt, sp: Span, trait_def_id: DefId) {
138     if tcx.sess.features.borrow().unboxed_closures {
139         // the feature gate allows all of them
140         return;
141     }
142     let did = Some(trait_def_id);
143     let li = &tcx.lang_items;
144
145     let trait_name = if did == li.fn_trait() {
146         "Fn"
147     } else if did == li.fn_mut_trait() {
148         "FnMut"
149     } else if did == li.fn_once_trait() {
150         "FnOnce"
151     } else {
152         return; // everything OK
153     };
154     let mut err = struct_span_err!(tcx.sess,
155                                    sp,
156                                    E0183,
157                                    "manual implementations of `{}` are experimental",
158                                    trait_name);
159     help!(&mut err,
160           "add `#![feature(unboxed_closures)]` to the crate attributes to enable");
161     err.emit();
162 }
163
164 pub fn check_coherence(ccx: &CrateCtxt) {
165     let _task = ccx.tcx.dep_graph.in_task(DepNode::Coherence);
166     CoherenceChecker { tcx: ccx.tcx }.check();
167     unsafety::check(ccx.tcx);
168     orphan::check(ccx.tcx);
169     overlap::check(ccx.tcx);
170     builtin::check(ccx.tcx);
171 }