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.
66 #![crate_name = "rustc_typeck"]
67 #![unstable(feature = "rustc_private")]
69 #![crate_type = "dylib"]
70 #![crate_type = "rlib"]
71 #![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
72 html_favicon_url = "http://www.rust-lang.org/favicon.ico",
73 html_root_url = "http://doc.rust-lang.org/nightly/")]
75 #![allow(non_camel_case_types)]
77 #![feature(box_syntax)]
78 #![feature(collections)]
82 #![feature(rustc_diagnostic_macros)]
83 #![feature(rustc_private)]
84 #![feature(slicing_syntax, unsafe_destructor)]
85 #![feature(staged_api)]
88 #[macro_use] extern crate log;
89 #[macro_use] extern crate syntax;
92 extern crate fmt_macros;
96 pub use rustc::metadata;
97 pub use rustc::middle;
98 pub use rustc::session;
104 use middle::subst::VecPerParamSpace;
105 use middle::ty::{self, Ty};
107 use util::common::time;
108 use util::ppaux::Repr;
111 use syntax::codemap::Span;
112 use syntax::print::pprust::*;
113 use syntax::{ast, ast_map, abi};
114 use syntax::ast_util::local_def;
116 use std::cell::RefCell;
118 // NB: This module needs to be declared first so diagnostics are
119 // registered before they are used.
129 struct TypeAndSubsts<'tcx> {
130 pub substs: subst::Substs<'tcx>,
134 struct CrateCtxt<'a, 'tcx: 'a> {
135 // A mapping from method call sites to traits that have that method.
136 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 all_traits: RefCell<Option<check::method::AllTraitsVec>>,
142 tcx: &'a ty::ctxt<'tcx>,
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, ppaux::ty_to_string(tcx, ty));
148 assert!(!ty::type_needs_infer(ty));
149 tcx.node_types.borrow_mut().insert(node_id, ty);
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({}, {})",
158 item_substs.repr(tcx));
160 assert!(item_substs.substs.types.all(|t| !ty::type_needs_infer(*t)));
162 tcx.item_substs.borrow_mut().insert(node_id, item_substs);
165 fn lookup_def_tcx(tcx:&ty::ctxt, sp: Span, id: ast::NodeId) -> def::Def {
166 match tcx.def_map.borrow().get(&id) {
167 Some(x) => x.clone(),
169 span_fatal!(tcx.sess, sp, E0242, "internal error looking up a definition")
174 fn lookup_def_ccx(ccx: &CrateCtxt, sp: Span, id: ast::NodeId)
176 lookup_def_tcx(ccx.tcx, sp, id)
179 fn no_params<'tcx>(t: Ty<'tcx>) -> ty::TypeScheme<'tcx> {
181 generics: ty::Generics {
182 types: VecPerParamSpace::empty(),
183 regions: VecPerParamSpace::empty(),
184 predicates: VecPerParamSpace::empty(),
190 fn require_same_types<'a, 'tcx, M>(tcx: &ty::ctxt<'tcx>,
191 maybe_infcx: Option<&infer::InferCtxt<'a, 'tcx>>,
192 t1_is_expected: bool,
198 M: FnOnce() -> String,
200 let result = match maybe_infcx {
202 let infcx = infer::new_infer_ctxt(tcx);
203 infer::mk_eqty(&infcx, t1_is_expected, infer::Misc(span), t1, t2)
206 infer::mk_eqty(infcx, t1_is_expected, infer::Misc(span), t1, t2)
213 span_err!(tcx.sess, span, E0211,
216 ty::type_err_to_str(tcx,
218 ty::note_and_explain_type_err(tcx, terr);
224 fn check_main_fn_ty(ccx: &CrateCtxt,
225 main_id: ast::NodeId,
228 let main_t = ty::node_id_to_type(tcx, main_id);
230 ty::ty_bare_fn(..) => {
231 match tcx.map.find(main_id) {
232 Some(ast_map::NodeItem(it)) => {
234 ast::ItemFn(_, _, _, ref ps, _)
235 if ps.is_parameterized() => {
236 span_err!(ccx.tcx.sess, main_span, E0131,
237 "main function is not allowed to have type parameters");
245 let se_ty = ty::mk_bare_fn(tcx, Some(local_def(main_id)), tcx.mk_bare_fn(ty::BareFnTy {
246 unsafety: ast::Unsafety::Normal,
248 sig: ty::Binder(ty::FnSig {
250 output: ty::FnConverging(ty::mk_nil(tcx)),
255 require_same_types(tcx, None, false, main_span, main_t, se_ty,
257 format!("main function expects type: `{}`",
258 ppaux::ty_to_string(ccx.tcx, se_ty))
262 tcx.sess.span_bug(main_span,
263 &format!("main has a non-function type: found \
265 ppaux::ty_to_string(tcx,
271 fn check_start_fn_ty(ccx: &CrateCtxt,
272 start_id: ast::NodeId,
275 let start_t = ty::node_id_to_type(tcx, start_id);
277 ty::ty_bare_fn(..) => {
278 match tcx.map.find(start_id) {
279 Some(ast_map::NodeItem(it)) => {
281 ast::ItemFn(_,_,_,ref ps,_)
282 if ps.is_parameterized() => {
283 span_err!(tcx.sess, start_span, E0132,
284 "start function is not allowed to have type parameters");
293 let se_ty = ty::mk_bare_fn(tcx, Some(local_def(start_id)), tcx.mk_bare_fn(ty::BareFnTy {
294 unsafety: ast::Unsafety::Normal,
296 sig: ty::Binder(ty::FnSig {
299 ty::mk_imm_ptr(tcx, ty::mk_imm_ptr(tcx, tcx.types.u8))
301 output: ty::FnConverging(tcx.types.int),
306 require_same_types(tcx, None, false, start_span, start_t, se_ty,
308 format!("start function expects type: `{}`",
309 ppaux::ty_to_string(ccx.tcx, se_ty))
314 tcx.sess.span_bug(start_span,
315 &format!("start has a non-function type: found \
317 ppaux::ty_to_string(tcx, start_t))[]);
322 fn check_for_entry_fn(ccx: &CrateCtxt) {
324 match *tcx.sess.entry_fn.borrow() {
325 Some((id, sp)) => match tcx.sess.entry_type.get() {
326 Some(config::EntryMain) => check_main_fn_ty(ccx, id, sp),
327 Some(config::EntryStart) => check_start_fn_ty(ccx, id, sp),
328 Some(config::EntryNone) => {}
329 None => tcx.sess.bug("entry function without a type")
335 pub fn check_crate(tcx: &ty::ctxt, trait_map: ty::TraitMap) {
336 let time_passes = tcx.sess.time_passes();
337 let ccx = CrateCtxt {
338 trait_map: trait_map,
339 all_traits: RefCell::new(None),
343 time(time_passes, "type collecting", (), |_|
344 collect::collect_item_types(tcx));
346 // this ensures that later parts of type checking can assume that items
347 // have valid types and not error
348 tcx.sess.abort_if_errors();
350 time(time_passes, "variance inference", (), |_|
351 variance::infer_variance(tcx));
353 time(time_passes, "coherence checking", (), |_|
354 coherence::check_coherence(&ccx));
356 time(time_passes, "type checking", (), |_|
357 check::check_item_types(&ccx));
359 check_for_entry_fn(&ccx);
360 tcx.sess.abort_if_errors();