]> git.lizzy.rs Git - rust.git/blob - src/librustc_typeck/lib.rs
Rollup merge of #30136 - fhahn:remove-int-from-doc-examples, r=steveklabnik
[rust.git] / src / librustc_typeck / lib.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 /*!
12
13 typeck.rs, an introduction
14
15 The type checker is responsible for:
16
17 1. Determining the type of each expression
18 2. Resolving methods and traits
19 3. Guaranteeing that most type rules are met ("most?", you say, "why most?"
20    Well, dear reader, read on)
21
22 The main entry point is `check_crate()`.  Type checking operates in
23 several major phases:
24
25 1. The collect phase first passes over all items and determines their
26    type, without examining their "innards".
27
28 2. Variance inference then runs to compute the variance of each parameter
29
30 3. Coherence checks for overlapping or orphaned impls
31
32 4. Finally, the check phase then checks function bodies and so forth.
33    Within the check phase, we check each function body one at a time
34    (bodies of function expressions are checked as part of the
35    containing function).  Inference is used to supply types wherever
36    they are unknown. The actual checking of a function itself has
37    several phases (check, regionck, writeback), as discussed in the
38    documentation for the `check` module.
39
40 The type checker is defined into various submodules which are documented
41 independently:
42
43 - astconv: converts the AST representation of types
44   into the `ty` representation
45
46 - collect: computes the types of each top-level item and enters them into
47   the `cx.tcache` table for later use
48
49 - coherence: enforces coherence rules, builds some tables
50
51 - variance: variance inference
52
53 - check: walks over function bodies and type checks them, inferring types for
54   local variables, type parameters, etc as necessary.
55
56 - infer: finds the types to use for each type variable such that
57   all subtyping and assignment constraints are met.  In essence, the check
58   module specifies the constraints, and the infer module solves them.
59
60 # Note
61
62 This API is completely unstable and subject to change.
63
64 */
65 // Do not remove on snapshot creation. Needed for bootstrap. (Issue #22364)
66 #![cfg_attr(stage0, feature(custom_attribute))]
67 #![crate_name = "rustc_typeck"]
68 #![unstable(feature = "rustc_private", issue = "27812")]
69 #![cfg_attr(stage0, staged_api)]
70 #![crate_type = "dylib"]
71 #![crate_type = "rlib"]
72 #![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
73       html_favicon_url = "https://doc.rust-lang.org/favicon.ico",
74       html_root_url = "https://doc.rust-lang.org/nightly/")]
75
76 #![allow(non_camel_case_types)]
77
78 #![feature(box_patterns)]
79 #![feature(box_syntax)]
80 #![feature(drain)]
81 #![feature(iter_cmp)]
82 #![feature(iter_arith)]
83 #![feature(quote)]
84 #![feature(rustc_diagnostic_macros)]
85 #![feature(rustc_private)]
86 #![feature(staged_api)]
87 #![feature(vec_push_all)]
88 #![feature(cell_extras)]
89
90 #[macro_use] extern crate log;
91 #[macro_use] extern crate syntax;
92
93 extern crate arena;
94 extern crate fmt_macros;
95 extern crate rustc;
96 extern crate rustc_platform_intrinsics as intrinsics;
97 extern crate rustc_front;
98 extern crate rustc_back;
99
100 pub use rustc::front;
101 pub use rustc::lint;
102 pub use rustc::middle;
103 pub use rustc::session;
104 pub use rustc::util;
105
106 use front::map as hir_map;
107 use middle::def;
108 use middle::infer::{self, TypeOrigin};
109 use middle::subst;
110 use middle::ty::{self, Ty, HasTypeFlags};
111 use session::config;
112 use util::common::time;
113 use rustc_front::hir;
114
115 use syntax::codemap::Span;
116 use syntax::print::pprust::*;
117 use syntax::{ast, abi};
118
119 use std::cell::RefCell;
120
121 // NB: This module needs to be declared first so diagnostics are
122 // registered before they are used.
123 pub mod diagnostics;
124
125 pub mod check;
126 mod rscope;
127 mod astconv;
128 pub mod collect;
129 mod constrained_type_params;
130 pub mod coherence;
131 pub mod variance;
132
133 pub struct TypeAndSubsts<'tcx> {
134     pub substs: subst::Substs<'tcx>,
135     pub ty: Ty<'tcx>,
136 }
137
138 pub struct CrateCtxt<'a, 'tcx: 'a> {
139     // A mapping from method call sites to traits that have that method.
140     pub trait_map: ty::TraitMap,
141     /// A vector of every trait accessible in the whole crate
142     /// (i.e. including those from subcrates). This is used only for
143     /// error reporting, and so is lazily initialised and generally
144     /// shouldn't taint the common path (hence the RefCell).
145     pub all_traits: RefCell<Option<check::method::AllTraitsVec>>,
146     pub tcx: &'a ty::ctxt<'tcx>,
147 }
148
149 // Functions that write types into the node type table
150 fn write_ty_to_tcx<'tcx>(tcx: &ty::ctxt<'tcx>, node_id: ast::NodeId, ty: Ty<'tcx>) {
151     debug!("write_ty_to_tcx({}, {:?})", node_id,  ty);
152     assert!(!ty.needs_infer());
153     tcx.node_type_insert(node_id, ty);
154 }
155
156 fn write_substs_to_tcx<'tcx>(tcx: &ty::ctxt<'tcx>,
157                                  node_id: ast::NodeId,
158                                  item_substs: ty::ItemSubsts<'tcx>) {
159     if !item_substs.is_noop() {
160         debug!("write_substs_to_tcx({}, {:?})",
161                node_id,
162                item_substs);
163
164         assert!(!item_substs.substs.types.needs_infer());
165
166         tcx.tables.borrow_mut().item_substs.insert(node_id, item_substs);
167     }
168 }
169
170 fn lookup_full_def(tcx: &ty::ctxt, sp: Span, id: ast::NodeId) -> def::Def {
171     match tcx.def_map.borrow().get(&id) {
172         Some(x) => x.full_def(),
173         None => {
174             span_fatal!(tcx.sess, sp, E0242, "internal error looking up a definition")
175         }
176     }
177 }
178
179 fn require_c_abi_if_variadic(tcx: &ty::ctxt,
180                              decl: &hir::FnDecl,
181                              abi: abi::Abi,
182                              span: Span) {
183     if decl.variadic && abi != abi::C {
184         span_err!(tcx.sess, span, E0045,
185                   "variadic function must have C calling convention");
186     }
187 }
188
189 fn require_same_types<'a, 'tcx, M>(tcx: &ty::ctxt<'tcx>,
190                                    maybe_infcx: Option<&infer::InferCtxt<'a, 'tcx>>,
191                                    t1_is_expected: bool,
192                                    span: Span,
193                                    t1: Ty<'tcx>,
194                                    t2: Ty<'tcx>,
195                                    msg: M)
196                                    -> bool where
197     M: FnOnce() -> String,
198 {
199     let result = match maybe_infcx {
200         None => {
201             let infcx = infer::new_infer_ctxt(tcx, &tcx.tables, None, false);
202             infer::mk_eqty(&infcx, t1_is_expected, TypeOrigin::Misc(span), t1, t2)
203         }
204         Some(infcx) => {
205             infer::mk_eqty(infcx, t1_is_expected, TypeOrigin::Misc(span), t1, t2)
206         }
207     };
208
209     match result {
210         Ok(_) => true,
211         Err(ref terr) => {
212             span_err!(tcx.sess, span, E0211, "{}: {}", msg(), terr);
213             tcx.note_and_explain_type_err(terr, span);
214             false
215         }
216     }
217 }
218
219 fn check_main_fn_ty(ccx: &CrateCtxt,
220                     main_id: ast::NodeId,
221                     main_span: Span) {
222     let tcx = ccx.tcx;
223     let main_t = tcx.node_id_to_type(main_id);
224     match main_t.sty {
225         ty::TyBareFn(..) => {
226             match tcx.map.find(main_id) {
227                 Some(hir_map::NodeItem(it)) => {
228                     match it.node {
229                         hir::ItemFn(_, _, _, _, ref ps, _)
230                         if ps.is_parameterized() => {
231                             span_err!(ccx.tcx.sess, main_span, E0131,
232                                       "main function is not allowed to have type parameters");
233                             return;
234                         }
235                         _ => ()
236                     }
237                 }
238                 _ => ()
239             }
240             let main_def_id = tcx.map.local_def_id(main_id);
241             let se_ty = tcx.mk_fn(Some(main_def_id), tcx.mk_bare_fn(ty::BareFnTy {
242                 unsafety: hir::Unsafety::Normal,
243                 abi: abi::Rust,
244                 sig: ty::Binder(ty::FnSig {
245                     inputs: Vec::new(),
246                     output: ty::FnConverging(tcx.mk_nil()),
247                     variadic: false
248                 })
249             }));
250
251             require_same_types(tcx, None, false, main_span, main_t, se_ty,
252                 || {
253                     format!("main function expects type: `{}`",
254                              se_ty)
255                 });
256         }
257         _ => {
258             tcx.sess.span_bug(main_span,
259                               &format!("main has a non-function type: found `{}`",
260                                        main_t));
261         }
262     }
263 }
264
265 fn check_start_fn_ty(ccx: &CrateCtxt,
266                      start_id: ast::NodeId,
267                      start_span: Span) {
268     let tcx = ccx.tcx;
269     let start_t = tcx.node_id_to_type(start_id);
270     match start_t.sty {
271         ty::TyBareFn(..) => {
272             match tcx.map.find(start_id) {
273                 Some(hir_map::NodeItem(it)) => {
274                     match it.node {
275                         hir::ItemFn(_,_,_,_,ref ps,_)
276                         if ps.is_parameterized() => {
277                             span_err!(tcx.sess, start_span, E0132,
278                                       "start function is not allowed to have type parameters");
279                             return;
280                         }
281                         _ => ()
282                     }
283                 }
284                 _ => ()
285             }
286
287             let se_ty = tcx.mk_fn(Some(ccx.tcx.map.local_def_id(start_id)),
288                                   tcx.mk_bare_fn(ty::BareFnTy {
289                 unsafety: hir::Unsafety::Normal,
290                 abi: abi::Rust,
291                 sig: ty::Binder(ty::FnSig {
292                     inputs: vec!(
293                         tcx.types.isize,
294                         tcx.mk_imm_ptr(tcx.mk_imm_ptr(tcx.types.u8))
295                     ),
296                     output: ty::FnConverging(tcx.types.isize),
297                     variadic: false,
298                 }),
299             }));
300
301             require_same_types(tcx, None, false, start_span, start_t, se_ty,
302                 || {
303                     format!("start function expects type: `{}`",
304                              se_ty)
305                 });
306
307         }
308         _ => {
309             tcx.sess.span_bug(start_span,
310                               &format!("start has a non-function type: found `{}`",
311                                        start_t));
312         }
313     }
314 }
315
316 fn check_for_entry_fn(ccx: &CrateCtxt) {
317     let tcx = ccx.tcx;
318     match *tcx.sess.entry_fn.borrow() {
319         Some((id, sp)) => match tcx.sess.entry_type.get() {
320             Some(config::EntryMain) => check_main_fn_ty(ccx, id, sp),
321             Some(config::EntryStart) => check_start_fn_ty(ccx, id, sp),
322             Some(config::EntryNone) => {}
323             None => tcx.sess.bug("entry function without a type")
324         },
325         None => {}
326     }
327 }
328
329 pub fn check_crate(tcx: &ty::ctxt, trait_map: ty::TraitMap) {
330     let time_passes = tcx.sess.time_passes();
331     let ccx = CrateCtxt {
332         trait_map: trait_map,
333         all_traits: RefCell::new(None),
334         tcx: tcx
335     };
336
337     time(time_passes, "type collecting", ||
338          collect::collect_item_types(tcx));
339
340     // this ensures that later parts of type checking can assume that items
341     // have valid types and not error
342     tcx.sess.abort_if_errors();
343
344     time(time_passes, "variance inference", ||
345          variance::infer_variance(tcx));
346
347     time(time_passes, "coherence checking", ||
348         coherence::check_coherence(&ccx));
349
350     time(time_passes, "wf checking (old)", ||
351         check::check_wf_old(&ccx));
352
353     time(time_passes, "item-types checking", ||
354         check::check_item_types(&ccx));
355
356     time(time_passes, "item-bodies checking", ||
357         check::check_item_bodies(&ccx));
358
359     time(time_passes, "drop-impl checking", ||
360         check::check_drop_impls(&ccx));
361
362     // Do this last so that if there are errors in the old code, they
363     // get reported, and we don't get extra warnings.
364     time(time_passes, "wf checking (new)", ||
365         check::check_wf_new(&ccx));
366
367     check_for_entry_fn(&ccx);
368     tcx.sess.abort_if_errors();
369 }
370
371 __build_diagnostic_array! { librustc_typeck, DIAGNOSTICS }