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.
13 typeck.rs, an introduction
15 The type checker is responsible for:
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)
22 The main entry point is `check_crate()`. Type checking operates in
25 1. The collect phase first passes over all items and determines their
26 type, without examining their "innards".
28 2. Variance inference then runs to compute the variance of each parameter
30 3. Coherence checks for overlapping or orphaned impls
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.
40 The type checker is defined into various submodules which are documented
43 - astconv: converts the AST representation of types
44 into the `ty` representation
46 - collect: computes the types of each top-level item and enters them into
47 the `cx.tcache` table for later use
49 - coherence: enforces coherence rules, builds some tables
51 - variance: variance inference
53 - check: walks over function bodies and type checks them, inferring types for
54 local variables, type parameters, etc as necessary.
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.
62 This API is completely unstable and subject to change.
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")]
70 #![crate_type = "dylib"]
71 #![crate_type = "rlib"]
72 #![doc(html_logo_url = "http://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 = "http://doc.rust-lang.org/nightly/")]
76 #![allow(non_camel_case_types)]
79 #![feature(box_patterns)]
80 #![feature(box_syntax)]
83 #![feature(iter_arith)]
85 #![feature(ref_slice)]
86 #![feature(rustc_diagnostic_macros)]
87 #![feature(rustc_private)]
88 #![feature(slice_extras)]
89 #![feature(staged_api)]
90 #![feature(vec_push_all)]
91 #![feature(cell_extras)]
93 #[macro_use] extern crate log;
94 #[macro_use] extern crate syntax;
97 extern crate fmt_macros;
101 pub use rustc::metadata;
102 pub use rustc::middle;
103 pub use rustc::session;
109 use middle::ty::{self, Ty, HasTypeFlags};
112 use util::common::time;
114 use syntax::codemap::Span;
115 use syntax::print::pprust::*;
116 use syntax::{ast, abi};
117 use syntax::ast_util::local_def;
119 use std::cell::RefCell;
121 // NB: This module needs to be declared first so diagnostics are
122 // registered before they are used.
129 mod constrained_type_params;
133 pub struct TypeAndSubsts<'tcx> {
134 pub substs: subst::Substs<'tcx>,
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>,
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);
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({}, {:?})",
164 assert!(!item_substs.substs.types.needs_infer());
166 tcx.tables.borrow_mut().item_substs.insert(node_id, item_substs);
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(),
174 span_fatal!(tcx.sess, sp, E0242, "internal error looking up a definition")
179 fn require_same_types<'a, 'tcx, M>(tcx: &ty::ctxt<'tcx>,
180 maybe_infcx: Option<&infer::InferCtxt<'a, 'tcx>>,
181 t1_is_expected: bool,
187 M: FnOnce() -> String,
189 let result = match maybe_infcx {
191 let infcx = infer::new_infer_ctxt(tcx, &tcx.tables, None);
192 infer::mk_eqty(&infcx, t1_is_expected, infer::Misc(span), t1, t2)
195 infer::mk_eqty(infcx, t1_is_expected, infer::Misc(span), t1, t2)
202 span_err!(tcx.sess, span, E0211, "{}: {}", msg(), terr);
203 tcx.note_and_explain_type_err(terr, span);
209 fn check_main_fn_ty(ccx: &CrateCtxt,
210 main_id: ast::NodeId,
213 let main_t = tcx.node_id_to_type(main_id);
215 ty::TyBareFn(..) => {
216 match tcx.map.find(main_id) {
217 Some(ast_map::NodeItem(it)) => {
219 ast::ItemFn(_, _, _, _, ref ps, _)
220 if ps.is_parameterized() => {
221 span_err!(ccx.tcx.sess, main_span, E0131,
222 "main function is not allowed to have type parameters");
230 let se_ty = tcx.mk_fn(Some(local_def(main_id)), tcx.mk_bare_fn(ty::BareFnTy {
231 unsafety: ast::Unsafety::Normal,
233 sig: ty::Binder(ty::FnSig {
235 output: ty::FnConverging(tcx.mk_nil()),
240 require_same_types(tcx, None, false, main_span, main_t, se_ty,
242 format!("main function expects type: `{}`",
247 tcx.sess.span_bug(main_span,
248 &format!("main has a non-function type: found `{}`",
254 fn check_start_fn_ty(ccx: &CrateCtxt,
255 start_id: ast::NodeId,
258 let start_t = tcx.node_id_to_type(start_id);
260 ty::TyBareFn(..) => {
261 match tcx.map.find(start_id) {
262 Some(ast_map::NodeItem(it)) => {
264 ast::ItemFn(_,_,_,_,ref ps,_)
265 if ps.is_parameterized() => {
266 span_err!(tcx.sess, start_span, E0132,
267 "start function is not allowed to have type parameters");
276 let se_ty = tcx.mk_fn(Some(local_def(start_id)), tcx.mk_bare_fn(ty::BareFnTy {
277 unsafety: ast::Unsafety::Normal,
279 sig: ty::Binder(ty::FnSig {
282 tcx.mk_imm_ptr(tcx.mk_imm_ptr(tcx.types.u8))
284 output: ty::FnConverging(tcx.types.isize),
289 require_same_types(tcx, None, false, start_span, start_t, se_ty,
291 format!("start function expects type: `{}`",
297 tcx.sess.span_bug(start_span,
298 &format!("start has a non-function type: found `{}`",
304 fn check_for_entry_fn(ccx: &CrateCtxt) {
306 match *tcx.sess.entry_fn.borrow() {
307 Some((id, sp)) => match tcx.sess.entry_type.get() {
308 Some(config::EntryMain) => check_main_fn_ty(ccx, id, sp),
309 Some(config::EntryStart) => check_start_fn_ty(ccx, id, sp),
310 Some(config::EntryNone) => {}
311 None => tcx.sess.bug("entry function without a type")
317 pub fn check_crate(tcx: &ty::ctxt, trait_map: ty::TraitMap) {
318 let time_passes = tcx.sess.time_passes();
319 let ccx = CrateCtxt {
320 trait_map: trait_map,
321 all_traits: RefCell::new(None),
325 time(time_passes, "type collecting", (), |_|
326 collect::collect_item_types(tcx));
328 // this ensures that later parts of type checking can assume that items
329 // have valid types and not error
330 tcx.sess.abort_if_errors();
332 time(time_passes, "variance inference", (), |_|
333 variance::infer_variance(tcx));
335 time(time_passes, "coherence checking", (), |_|
336 coherence::check_coherence(&ccx));
338 time(time_passes, "type checking", (), |_|
339 check::check_item_types(&ccx));
341 check_for_entry_fn(&ccx);
342 tcx.sess.abort_if_errors();
345 __build_diagnostic_array! { librustc_typeck, DIAGNOSTICS }