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_splits)]
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_c_abi_if_variadic(tcx: &ty::ctxt,
183 if decl.variadic && abi != abi::C {
184 span_err!(tcx.sess, span, E0045,
185 "variadic function must have C calling convention");
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,
197 M: FnOnce() -> String,
199 let result = match maybe_infcx {
201 let infcx = infer::new_infer_ctxt(tcx, &tcx.tables, None, false);
202 infer::mk_eqty(&infcx, t1_is_expected, infer::Misc(span), t1, t2)
205 infer::mk_eqty(infcx, t1_is_expected, infer::Misc(span), t1, t2)
212 span_err!(tcx.sess, span, E0211, "{}: {}", msg(), terr);
213 tcx.note_and_explain_type_err(terr, span);
219 fn check_main_fn_ty(ccx: &CrateCtxt,
220 main_id: ast::NodeId,
223 let main_t = tcx.node_id_to_type(main_id);
225 ty::TyBareFn(..) => {
226 match tcx.map.find(main_id) {
227 Some(ast_map::NodeItem(it)) => {
229 ast::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");
240 let se_ty = tcx.mk_fn(Some(local_def(main_id)), tcx.mk_bare_fn(ty::BareFnTy {
241 unsafety: ast::Unsafety::Normal,
243 sig: ty::Binder(ty::FnSig {
245 output: ty::FnConverging(tcx.mk_nil()),
250 require_same_types(tcx, None, false, main_span, main_t, se_ty,
252 format!("main function expects type: `{}`",
257 tcx.sess.span_bug(main_span,
258 &format!("main has a non-function type: found `{}`",
264 fn check_start_fn_ty(ccx: &CrateCtxt,
265 start_id: ast::NodeId,
268 let start_t = tcx.node_id_to_type(start_id);
270 ty::TyBareFn(..) => {
271 match tcx.map.find(start_id) {
272 Some(ast_map::NodeItem(it)) => {
274 ast::ItemFn(_,_,_,_,ref ps,_)
275 if ps.is_parameterized() => {
276 span_err!(tcx.sess, start_span, E0132,
277 "start function is not allowed to have type parameters");
286 let se_ty = tcx.mk_fn(Some(local_def(start_id)), tcx.mk_bare_fn(ty::BareFnTy {
287 unsafety: ast::Unsafety::Normal,
289 sig: ty::Binder(ty::FnSig {
292 tcx.mk_imm_ptr(tcx.mk_imm_ptr(tcx.types.u8))
294 output: ty::FnConverging(tcx.types.isize),
299 require_same_types(tcx, None, false, start_span, start_t, se_ty,
301 format!("start function expects type: `{}`",
307 tcx.sess.span_bug(start_span,
308 &format!("start has a non-function type: found `{}`",
314 fn check_for_entry_fn(ccx: &CrateCtxt) {
316 match *tcx.sess.entry_fn.borrow() {
317 Some((id, sp)) => match tcx.sess.entry_type.get() {
318 Some(config::EntryMain) => check_main_fn_ty(ccx, id, sp),
319 Some(config::EntryStart) => check_start_fn_ty(ccx, id, sp),
320 Some(config::EntryNone) => {}
321 None => tcx.sess.bug("entry function without a type")
327 pub fn check_crate(tcx: &ty::ctxt, trait_map: ty::TraitMap) {
328 let time_passes = tcx.sess.time_passes();
329 let ccx = CrateCtxt {
330 trait_map: trait_map,
331 all_traits: RefCell::new(None),
335 time(time_passes, "type collecting", (), |_|
336 collect::collect_item_types(tcx));
338 // this ensures that later parts of type checking can assume that items
339 // have valid types and not error
340 tcx.sess.abort_if_errors();
342 time(time_passes, "variance inference", (), |_|
343 variance::infer_variance(tcx));
345 time(time_passes, "coherence checking", (), |_|
346 coherence::check_coherence(&ccx));
348 time(time_passes, "type checking", (), |_|
349 check::check_item_types(&ccx));
351 check_for_entry_fn(&ccx);
352 tcx.sess.abort_if_errors();
355 __build_diagnostic_array! { librustc_typeck, DIAGNOSTICS }