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", issue = "27812")]
68 #![crate_type = "dylib"]
69 #![crate_type = "rlib"]
70 #![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
71 html_favicon_url = "https://doc.rust-lang.org/favicon.ico",
72 html_root_url = "https://doc.rust-lang.org/nightly/")]
74 #![allow(non_camel_case_types)]
76 #![feature(box_patterns)]
77 #![feature(box_syntax)]
78 #![feature(iter_arith)]
80 #![feature(rustc_diagnostic_macros)]
81 #![feature(rustc_private)]
82 #![feature(staged_api)]
83 #![feature(cell_extras)]
85 #[macro_use] extern crate log;
86 #[macro_use] extern crate syntax;
89 extern crate fmt_macros;
91 extern crate rustc_platform_intrinsics as intrinsics;
92 extern crate rustc_front;
93 extern crate rustc_back;
97 pub use rustc::middle;
98 pub use rustc::session;
101 use front::map as hir_map;
103 use middle::infer::{self, TypeOrigin};
105 use middle::ty::{self, Ty, HasTypeFlags};
107 use util::common::time;
108 use rustc_front::hir;
110 use syntax::codemap::Span;
111 use syntax::{ast, abi};
113 use std::cell::RefCell;
115 // NB: This module needs to be declared first so diagnostics are
116 // registered before they are used.
123 mod constrained_type_params;
127 pub struct TypeAndSubsts<'tcx> {
128 pub substs: subst::Substs<'tcx>,
132 pub struct CrateCtxt<'a, 'tcx: 'a> {
133 // A mapping from method call sites to traits that have that method.
134 pub trait_map: ty::TraitMap,
135 /// A vector of every trait accessible in the whole crate
136 /// (i.e. including those from subcrates). This is used only for
137 /// error reporting, and so is lazily initialised and generally
138 /// shouldn't taint the common path (hence the RefCell).
139 pub all_traits: RefCell<Option<check::method::AllTraitsVec>>,
140 pub tcx: &'a ty::ctxt<'tcx>,
143 // Functions that write types into the node type table
144 fn write_ty_to_tcx<'tcx>(tcx: &ty::ctxt<'tcx>, node_id: ast::NodeId, ty: Ty<'tcx>) {
145 debug!("write_ty_to_tcx({}, {:?})", node_id, ty);
146 assert!(!ty.needs_infer());
147 tcx.node_type_insert(node_id, ty);
150 fn write_substs_to_tcx<'tcx>(tcx: &ty::ctxt<'tcx>,
151 node_id: ast::NodeId,
152 item_substs: ty::ItemSubsts<'tcx>) {
153 if !item_substs.is_noop() {
154 debug!("write_substs_to_tcx({}, {:?})",
158 assert!(!item_substs.substs.types.needs_infer());
160 tcx.tables.borrow_mut().item_substs.insert(node_id, item_substs);
164 fn lookup_full_def(tcx: &ty::ctxt, sp: Span, id: ast::NodeId) -> def::Def {
165 match tcx.def_map.borrow().get(&id) {
166 Some(x) => x.full_def(),
168 span_fatal!(tcx.sess, sp, E0242, "internal error looking up a definition")
173 fn require_c_abi_if_variadic(tcx: &ty::ctxt,
177 if decl.variadic && abi != abi::C {
178 span_err!(tcx.sess, span, E0045,
179 "variadic function must have C calling convention");
183 fn require_same_types<'a, 'tcx, M>(tcx: &ty::ctxt<'tcx>,
184 maybe_infcx: Option<&infer::InferCtxt<'a, 'tcx>>,
185 t1_is_expected: bool,
191 M: FnOnce() -> String,
193 let result = match maybe_infcx {
195 let infcx = infer::new_infer_ctxt(tcx, &tcx.tables, None, false);
196 infer::mk_eqty(&infcx, t1_is_expected, TypeOrigin::Misc(span), t1, t2)
199 infer::mk_eqty(infcx, t1_is_expected, TypeOrigin::Misc(span), t1, t2)
206 let mut err = struct_span_err!(tcx.sess, span, E0211, "{}: {}", msg(), terr);
207 tcx.note_and_explain_type_err(&mut err, terr, span);
214 fn check_main_fn_ty(ccx: &CrateCtxt,
215 main_id: ast::NodeId,
218 let main_t = tcx.node_id_to_type(main_id);
220 ty::TyBareFn(..) => {
221 match tcx.map.find(main_id) {
222 Some(hir_map::NodeItem(it)) => {
224 hir::ItemFn(_, _, _, _, ref ps, _)
225 if ps.is_parameterized() => {
226 span_err!(ccx.tcx.sess, main_span, E0131,
227 "main function is not allowed to have type parameters");
235 let main_def_id = tcx.map.local_def_id(main_id);
236 let se_ty = tcx.mk_fn(Some(main_def_id), tcx.mk_bare_fn(ty::BareFnTy {
237 unsafety: hir::Unsafety::Normal,
239 sig: ty::Binder(ty::FnSig {
241 output: ty::FnConverging(tcx.mk_nil()),
246 require_same_types(tcx, None, false, main_span, main_t, se_ty,
248 format!("main function expects type: `{}`",
253 tcx.sess.span_bug(main_span,
254 &format!("main has a non-function type: found `{}`",
260 fn check_start_fn_ty(ccx: &CrateCtxt,
261 start_id: ast::NodeId,
264 let start_t = tcx.node_id_to_type(start_id);
266 ty::TyBareFn(..) => {
267 match tcx.map.find(start_id) {
268 Some(hir_map::NodeItem(it)) => {
270 hir::ItemFn(_,_,_,_,ref ps,_)
271 if ps.is_parameterized() => {
272 span_err!(tcx.sess, start_span, E0132,
273 "start function is not allowed to have type parameters");
282 let se_ty = tcx.mk_fn(Some(ccx.tcx.map.local_def_id(start_id)),
283 tcx.mk_bare_fn(ty::BareFnTy {
284 unsafety: hir::Unsafety::Normal,
286 sig: ty::Binder(ty::FnSig {
289 tcx.mk_imm_ptr(tcx.mk_imm_ptr(tcx.types.u8))
291 output: ty::FnConverging(tcx.types.isize),
296 require_same_types(tcx, None, false, start_span, start_t, se_ty,
298 format!("start function expects type: `{}`",
304 tcx.sess.span_bug(start_span,
305 &format!("start has a non-function type: found `{}`",
311 fn check_for_entry_fn(ccx: &CrateCtxt) {
313 match *tcx.sess.entry_fn.borrow() {
314 Some((id, sp)) => match tcx.sess.entry_type.get() {
315 Some(config::EntryMain) => check_main_fn_ty(ccx, id, sp),
316 Some(config::EntryStart) => check_start_fn_ty(ccx, id, sp),
317 Some(config::EntryNone) => {}
318 None => tcx.sess.bug("entry function without a type")
324 pub fn check_crate(tcx: &ty::ctxt, trait_map: ty::TraitMap) {
325 let time_passes = tcx.sess.time_passes();
326 let ccx = CrateCtxt {
327 trait_map: trait_map,
328 all_traits: RefCell::new(None),
332 // this ensures that later parts of type checking can assume that items
333 // have valid types and not error
334 tcx.sess.abort_if_new_errors(|| {
335 time(time_passes, "type collecting", ||
336 collect::collect_item_types(tcx));
340 time(time_passes, "variance inference", ||
341 variance::infer_variance(tcx));
343 tcx.sess.abort_if_new_errors(|| {
344 time(time_passes, "coherence checking", ||
345 coherence::check_coherence(&ccx));
348 time(time_passes, "wf checking", ||
349 check::check_wf_new(&ccx));
351 time(time_passes, "item-types checking", ||
352 check::check_item_types(&ccx));
354 time(time_passes, "item-bodies checking", ||
355 check::check_item_bodies(&ccx));
357 time(time_passes, "drop-impl checking", ||
358 check::check_drop_impls(&ccx));
360 check_for_entry_fn(&ccx);
361 tcx.sess.abort_if_errors();
364 __build_diagnostic_array! { librustc_typeck, DIAGNOSTICS }