]> git.lizzy.rs Git - rust.git/blob - src/librustc_typeck/lib.rs
Make RFC 1214 warnings into errors, and rip out the "warn or err"
[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(iter_arith)]
81 #![feature(quote)]
82 #![feature(rustc_diagnostic_macros)]
83 #![feature(rustc_private)]
84 #![feature(staged_api)]
85 #![feature(cell_extras)]
86
87 #[macro_use] extern crate log;
88 #[macro_use] extern crate syntax;
89
90 extern crate arena;
91 extern crate fmt_macros;
92 extern crate rustc;
93 extern crate rustc_platform_intrinsics as intrinsics;
94 extern crate rustc_front;
95 extern crate rustc_back;
96
97 pub use rustc::front;
98 pub use rustc::lint;
99 pub use rustc::middle;
100 pub use rustc::session;
101 pub use rustc::util;
102
103 use front::map as hir_map;
104 use middle::def;
105 use middle::infer::{self, TypeOrigin};
106 use middle::subst;
107 use middle::ty::{self, Ty, HasTypeFlags};
108 use session::config;
109 use util::common::time;
110 use rustc_front::hir;
111
112 use syntax::codemap::Span;
113 use syntax::{ast, abi};
114
115 use std::cell::RefCell;
116
117 // NB: This module needs to be declared first so diagnostics are
118 // registered before they are used.
119 pub mod diagnostics;
120
121 pub mod check;
122 mod rscope;
123 mod astconv;
124 pub mod collect;
125 mod constrained_type_params;
126 pub mod coherence;
127 pub mod variance;
128
129 pub struct TypeAndSubsts<'tcx> {
130     pub substs: subst::Substs<'tcx>,
131     pub ty: Ty<'tcx>,
132 }
133
134 pub struct CrateCtxt<'a, 'tcx: 'a> {
135     // A mapping from method call sites to traits that have that method.
136     pub trait_map: ty::TraitMap,
137     /// A vector of every trait accessible in the whole crate
138     /// (i.e. including those from subcrates). This is used only for
139     /// error reporting, and so is lazily initialised and generally
140     /// shouldn't taint the common path (hence the RefCell).
141     pub all_traits: RefCell<Option<check::method::AllTraitsVec>>,
142     pub tcx: &'a ty::ctxt<'tcx>,
143 }
144
145 // Functions that write types into the node type table
146 fn write_ty_to_tcx<'tcx>(tcx: &ty::ctxt<'tcx>, node_id: ast::NodeId, ty: Ty<'tcx>) {
147     debug!("write_ty_to_tcx({}, {:?})", node_id,  ty);
148     assert!(!ty.needs_infer());
149     tcx.node_type_insert(node_id, ty);
150 }
151
152 fn write_substs_to_tcx<'tcx>(tcx: &ty::ctxt<'tcx>,
153                                  node_id: ast::NodeId,
154                                  item_substs: ty::ItemSubsts<'tcx>) {
155     if !item_substs.is_noop() {
156         debug!("write_substs_to_tcx({}, {:?})",
157                node_id,
158                item_substs);
159
160         assert!(!item_substs.substs.types.needs_infer());
161
162         tcx.tables.borrow_mut().item_substs.insert(node_id, item_substs);
163     }
164 }
165
166 fn lookup_full_def(tcx: &ty::ctxt, sp: Span, id: ast::NodeId) -> def::Def {
167     match tcx.def_map.borrow().get(&id) {
168         Some(x) => x.full_def(),
169         None => {
170             span_fatal!(tcx.sess, sp, E0242, "internal error looking up a definition")
171         }
172     }
173 }
174
175 fn require_c_abi_if_variadic(tcx: &ty::ctxt,
176                              decl: &hir::FnDecl,
177                              abi: abi::Abi,
178                              span: Span) {
179     if decl.variadic && abi != abi::C {
180         span_err!(tcx.sess, span, E0045,
181                   "variadic function must have C calling convention");
182     }
183 }
184
185 fn require_same_types<'a, 'tcx, M>(tcx: &ty::ctxt<'tcx>,
186                                    maybe_infcx: Option<&infer::InferCtxt<'a, 'tcx>>,
187                                    t1_is_expected: bool,
188                                    span: Span,
189                                    t1: Ty<'tcx>,
190                                    t2: Ty<'tcx>,
191                                    msg: M)
192                                    -> bool where
193     M: FnOnce() -> String,
194 {
195     let result = match maybe_infcx {
196         None => {
197             let infcx = infer::new_infer_ctxt(tcx, &tcx.tables, None, false);
198             infer::mk_eqty(&infcx, t1_is_expected, TypeOrigin::Misc(span), t1, t2)
199         }
200         Some(infcx) => {
201             infer::mk_eqty(infcx, t1_is_expected, TypeOrigin::Misc(span), t1, t2)
202         }
203     };
204
205     match result {
206         Ok(_) => true,
207         Err(ref terr) => {
208             span_err!(tcx.sess, span, E0211, "{}: {}", msg(), terr);
209             tcx.note_and_explain_type_err(terr, span);
210             false
211         }
212     }
213 }
214
215 fn check_main_fn_ty(ccx: &CrateCtxt,
216                     main_id: ast::NodeId,
217                     main_span: Span) {
218     let tcx = ccx.tcx;
219     let main_t = tcx.node_id_to_type(main_id);
220     match main_t.sty {
221         ty::TyBareFn(..) => {
222             match tcx.map.find(main_id) {
223                 Some(hir_map::NodeItem(it)) => {
224                     match it.node {
225                         hir::ItemFn(_, _, _, _, ref ps, _)
226                         if ps.is_parameterized() => {
227                             span_err!(ccx.tcx.sess, main_span, E0131,
228                                       "main function is not allowed to have type parameters");
229                             return;
230                         }
231                         _ => ()
232                     }
233                 }
234                 _ => ()
235             }
236             let main_def_id = tcx.map.local_def_id(main_id);
237             let se_ty = tcx.mk_fn(Some(main_def_id), tcx.mk_bare_fn(ty::BareFnTy {
238                 unsafety: hir::Unsafety::Normal,
239                 abi: abi::Rust,
240                 sig: ty::Binder(ty::FnSig {
241                     inputs: Vec::new(),
242                     output: ty::FnConverging(tcx.mk_nil()),
243                     variadic: false
244                 })
245             }));
246
247             require_same_types(tcx, None, false, main_span, main_t, se_ty,
248                 || {
249                     format!("main function expects type: `{}`",
250                              se_ty)
251                 });
252         }
253         _ => {
254             tcx.sess.span_bug(main_span,
255                               &format!("main has a non-function type: found `{}`",
256                                        main_t));
257         }
258     }
259 }
260
261 fn check_start_fn_ty(ccx: &CrateCtxt,
262                      start_id: ast::NodeId,
263                      start_span: Span) {
264     let tcx = ccx.tcx;
265     let start_t = tcx.node_id_to_type(start_id);
266     match start_t.sty {
267         ty::TyBareFn(..) => {
268             match tcx.map.find(start_id) {
269                 Some(hir_map::NodeItem(it)) => {
270                     match it.node {
271                         hir::ItemFn(_,_,_,_,ref ps,_)
272                         if ps.is_parameterized() => {
273                             span_err!(tcx.sess, start_span, E0132,
274                                       "start function is not allowed to have type parameters");
275                             return;
276                         }
277                         _ => ()
278                     }
279                 }
280                 _ => ()
281             }
282
283             let se_ty = tcx.mk_fn(Some(ccx.tcx.map.local_def_id(start_id)),
284                                   tcx.mk_bare_fn(ty::BareFnTy {
285                 unsafety: hir::Unsafety::Normal,
286                 abi: abi::Rust,
287                 sig: ty::Binder(ty::FnSig {
288                     inputs: vec!(
289                         tcx.types.isize,
290                         tcx.mk_imm_ptr(tcx.mk_imm_ptr(tcx.types.u8))
291                     ),
292                     output: ty::FnConverging(tcx.types.isize),
293                     variadic: false,
294                 }),
295             }));
296
297             require_same_types(tcx, None, false, start_span, start_t, se_ty,
298                 || {
299                     format!("start function expects type: `{}`",
300                              se_ty)
301                 });
302
303         }
304         _ => {
305             tcx.sess.span_bug(start_span,
306                               &format!("start has a non-function type: found `{}`",
307                                        start_t));
308         }
309     }
310 }
311
312 fn check_for_entry_fn(ccx: &CrateCtxt) {
313     let tcx = ccx.tcx;
314     match *tcx.sess.entry_fn.borrow() {
315         Some((id, sp)) => match tcx.sess.entry_type.get() {
316             Some(config::EntryMain) => check_main_fn_ty(ccx, id, sp),
317             Some(config::EntryStart) => check_start_fn_ty(ccx, id, sp),
318             Some(config::EntryNone) => {}
319             None => tcx.sess.bug("entry function without a type")
320         },
321         None => {}
322     }
323 }
324
325 pub fn check_crate(tcx: &ty::ctxt, trait_map: ty::TraitMap) {
326     let time_passes = tcx.sess.time_passes();
327     let ccx = CrateCtxt {
328         trait_map: trait_map,
329         all_traits: RefCell::new(None),
330         tcx: tcx
331     };
332
333     // this ensures that later parts of type checking can assume that items
334     // have valid types and not error
335     tcx.sess.abort_if_new_errors(|| {
336         time(time_passes, "type collecting", ||
337              collect::collect_item_types(tcx));
338
339     });
340
341     time(time_passes, "variance inference", ||
342          variance::infer_variance(tcx));
343
344     tcx.sess.abort_if_new_errors(|| {
345       time(time_passes, "coherence checking", ||
346           coherence::check_coherence(&ccx));
347     });
348
349     time(time_passes, "wf checking", ||
350         check::check_wf_new(&ccx));
351
352     time(time_passes, "item-types checking", ||
353         check::check_item_types(&ccx));
354
355     time(time_passes, "item-bodies checking", ||
356         check::check_item_bodies(&ccx));
357
358     time(time_passes, "drop-impl checking", ||
359         check::check_drop_impls(&ccx));
360
361     check_for_entry_fn(&ccx);
362     tcx.sess.abort_if_errors();
363 }
364
365 __build_diagnostic_array! { librustc_typeck, DIAGNOSTICS }