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", 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/")]
76 #![allow(non_camel_case_types)]
78 #![feature(box_patterns)]
79 #![feature(box_syntax)]
80 #![feature(iter_arith)]
82 #![feature(rustc_diagnostic_macros)]
83 #![feature(rustc_private)]
84 #![feature(staged_api)]
85 #![feature(cell_extras)]
87 #[macro_use] extern crate log;
88 #[macro_use] extern crate syntax;
91 extern crate fmt_macros;
93 extern crate rustc_platform_intrinsics as intrinsics;
94 extern crate rustc_front;
95 extern crate rustc_back;
99 pub use rustc::middle;
100 pub use rustc::session;
103 use front::map as hir_map;
105 use middle::infer::{self, TypeOrigin};
107 use middle::ty::{self, Ty, HasTypeFlags};
109 use util::common::time;
110 use rustc_front::hir;
112 use syntax::codemap::Span;
113 use syntax::{ast, abi};
115 use std::cell::RefCell;
117 // NB: This module needs to be declared first so diagnostics are
118 // registered before they are used.
125 mod constrained_type_params;
129 pub struct TypeAndSubsts<'tcx> {
130 pub substs: subst::Substs<'tcx>,
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>,
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);
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({}, {:?})",
160 assert!(!item_substs.substs.types.needs_infer());
162 tcx.tables.borrow_mut().item_substs.insert(node_id, item_substs);
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(),
170 span_fatal!(tcx.sess, sp, E0242, "internal error looking up a definition")
175 fn require_c_abi_if_variadic(tcx: &ty::ctxt,
179 if decl.variadic && abi != abi::C {
180 span_err!(tcx.sess, span, E0045,
181 "variadic function must have C calling convention");
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,
193 M: FnOnce() -> String,
195 let result = match maybe_infcx {
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)
201 infer::mk_eqty(infcx, t1_is_expected, TypeOrigin::Misc(span), t1, t2)
208 span_err!(tcx.sess, span, E0211, "{}: {}", msg(), terr);
209 tcx.note_and_explain_type_err(terr, span);
215 fn check_main_fn_ty(ccx: &CrateCtxt,
216 main_id: ast::NodeId,
219 let main_t = tcx.node_id_to_type(main_id);
221 ty::TyBareFn(..) => {
222 match tcx.map.find(main_id) {
223 Some(hir_map::NodeItem(it)) => {
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");
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,
240 sig: ty::Binder(ty::FnSig {
242 output: ty::FnConverging(tcx.mk_nil()),
247 require_same_types(tcx, None, false, main_span, main_t, se_ty,
249 format!("main function expects type: `{}`",
254 tcx.sess.span_bug(main_span,
255 &format!("main has a non-function type: found `{}`",
261 fn check_start_fn_ty(ccx: &CrateCtxt,
262 start_id: ast::NodeId,
265 let start_t = tcx.node_id_to_type(start_id);
267 ty::TyBareFn(..) => {
268 match tcx.map.find(start_id) {
269 Some(hir_map::NodeItem(it)) => {
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");
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,
287 sig: ty::Binder(ty::FnSig {
290 tcx.mk_imm_ptr(tcx.mk_imm_ptr(tcx.types.u8))
292 output: ty::FnConverging(tcx.types.isize),
297 require_same_types(tcx, None, false, start_span, start_t, se_ty,
299 format!("start function expects type: `{}`",
305 tcx.sess.span_bug(start_span,
306 &format!("start has a non-function type: found `{}`",
312 fn check_for_entry_fn(ccx: &CrateCtxt) {
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")
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),
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));
341 time(time_passes, "variance inference", ||
342 variance::infer_variance(tcx));
344 tcx.sess.abort_if_new_errors(|| {
345 time(time_passes, "coherence checking", ||
346 coherence::check_coherence(&ccx));
349 time(time_passes, "wf checking (old)", ||
350 check::check_wf_old(&ccx));
352 time(time_passes, "item-types checking", ||
353 check::check_item_types(&ccx));
355 time(time_passes, "item-bodies checking", ||
356 check::check_item_bodies(&ccx));
358 time(time_passes, "drop-impl checking", ||
359 check::check_drop_impls(&ccx));
361 // Do this last so that if there are errors in the old code, they
362 // get reported, and we don't get extra warnings.
363 time(time_passes, "wf checking (new)", ||
364 check::check_wf_new(&ccx));
366 check_for_entry_fn(&ccx);
367 tcx.sess.abort_if_errors();
370 __build_diagnostic_array! { librustc_typeck, DIAGNOSTICS }