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 `tcx.types` 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 #![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
67 html_favicon_url = "https://doc.rust-lang.org/favicon.ico",
68 html_root_url = "https://doc.rust-lang.org/nightly/")]
71 #![allow(non_camel_case_types)]
73 #![feature(advanced_slice_patterns)]
74 #![feature(box_patterns)]
75 #![feature(box_syntax)]
76 #![feature(conservative_impl_trait)]
77 #![feature(never_type)]
79 #![feature(rustc_diagnostic_macros)]
80 #![feature(slice_patterns)]
82 #[macro_use] extern crate log;
83 #[macro_use] extern crate syntax;
84 extern crate syntax_pos;
87 #[macro_use] extern crate rustc;
88 extern crate rustc_platform_intrinsics as intrinsics;
89 extern crate rustc_back;
90 extern crate rustc_const_math;
91 extern crate rustc_data_structures;
92 extern crate rustc_errors as errors;
100 use hir::map as hir_map;
101 use rustc::infer::InferOk;
102 use rustc::ty::subst::Substs;
103 use rustc::ty::{self, Ty, TyCtxt};
104 use rustc::ty::maps::Providers;
105 use rustc::traits::{FulfillmentContext, ObligationCause, ObligationCauseCode, Reveal};
106 use session::{CompileIncomplete, config};
107 use util::common::time;
110 use syntax::abi::Abi;
111 use syntax_pos::Span;
114 // NB: This module needs to be declared first so diagnostics are
115 // registered before they are used.
122 mod constrained_type_params;
128 pub struct TypeAndSubsts<'tcx> {
129 substs: &'tcx Substs<'tcx>,
133 fn require_c_abi_if_variadic(tcx: TyCtxt,
137 if decl.variadic && !(abi == Abi::C || abi == Abi::Cdecl) {
138 let mut err = struct_span_err!(tcx.sess, span, E0045,
139 "variadic function must have C or cdecl calling convention");
140 err.span_label(span, "variadics require C or cdecl calling convention").emit();
144 fn require_same_types<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
145 cause: &ObligationCause<'tcx>,
149 tcx.infer_ctxt().enter(|ref infcx| {
150 let param_env = ty::ParamEnv::empty(Reveal::UserFacing);
151 let mut fulfill_cx = FulfillmentContext::new();
152 match infcx.at(&cause, param_env).eq(expected, actual) {
153 Ok(InferOk { obligations, .. }) => {
154 fulfill_cx.register_predicate_obligations(infcx, obligations);
157 infcx.report_mismatched_types(cause, expected, actual, err).emit();
162 match fulfill_cx.select_all_or_error(infcx) {
165 infcx.report_fulfillment_errors(&errors, None);
172 fn check_main_fn_ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
173 main_id: ast::NodeId,
175 let main_def_id = tcx.hir.local_def_id(main_id);
176 let main_t = tcx.type_of(main_def_id);
179 match tcx.hir.find(main_id) {
180 Some(hir_map::NodeItem(it)) => {
182 hir::ItemFn(.., ref generics, _) => {
183 if generics.is_parameterized() {
184 struct_span_err!(tcx.sess, generics.span, E0131,
185 "main function is not allowed to have type parameters")
186 .span_label(generics.span,
187 "main cannot have type parameters")
197 let se_ty = tcx.mk_fn_ptr(ty::Binder(
202 hir::Unsafety::Normal,
209 &ObligationCause::new(main_span, main_id, ObligationCauseCode::MainFunctionType),
211 tcx.mk_fn_ptr(tcx.fn_sig(main_def_id)));
215 "main has a non-function type: found `{}`",
221 fn check_start_fn_ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
222 start_id: ast::NodeId,
224 let start_def_id = tcx.hir.local_def_id(start_id);
225 let start_t = tcx.type_of(start_def_id);
228 match tcx.hir.find(start_id) {
229 Some(hir_map::NodeItem(it)) => {
231 hir::ItemFn(..,ref ps,_)
232 if ps.is_parameterized() => {
233 struct_span_err!(tcx.sess, ps.span, E0132,
234 "start function is not allowed to have type parameters")
236 "start function cannot have type parameters")
246 let se_ty = tcx.mk_fn_ptr(ty::Binder(
250 tcx.mk_imm_ptr(tcx.mk_imm_ptr(tcx.types.u8))
254 hir::Unsafety::Normal,
261 &ObligationCause::new(start_span, start_id, ObligationCauseCode::StartFunctionType),
263 tcx.mk_fn_ptr(tcx.fn_sig(start_def_id)));
266 span_bug!(start_span,
267 "start has a non-function type: found `{}`",
273 fn check_for_entry_fn<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
274 if let Some((id, sp)) = *tcx.sess.entry_fn.borrow() {
275 match tcx.sess.entry_type.get() {
276 Some(config::EntryMain) => check_main_fn_ty(tcx, id, sp),
277 Some(config::EntryStart) => check_start_fn_ty(tcx, id, sp),
278 Some(config::EntryNone) => {}
279 None => bug!("entry function without a type")
284 pub fn provide(providers: &mut Providers) {
285 collect::provide(providers);
286 coherence::provide(providers);
287 check::provide(providers);
288 variance::provide(providers);
291 pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>)
292 -> Result<(), CompileIncomplete>
294 let time_passes = tcx.sess.time_passes();
296 // this ensures that later parts of type checking can assume that items
297 // have valid types and not error
298 tcx.sess.track_errors(|| {
299 time(time_passes, "type collecting", ||
300 collect::collect_item_types(tcx));
304 tcx.sess.track_errors(|| {
305 time(time_passes, "impl wf inference", ||
306 impl_wf_check::impl_wf_check(tcx));
309 tcx.sess.track_errors(|| {
310 time(time_passes, "coherence checking", ||
311 coherence::check_coherence(tcx));
314 tcx.sess.track_errors(|| {
315 time(time_passes, "variance testing", ||
316 variance::test::test_variance(tcx));
319 time(time_passes, "wf checking", || check::check_wf_new(tcx))?;
321 time(time_passes, "item-types checking", || check::check_item_types(tcx))?;
323 time(time_passes, "item-bodies checking", || check::check_item_bodies(tcx))?;
325 check_unused::check_crate(tcx);
326 check_for_entry_fn(tcx);
328 tcx.sess.compile_status()
331 /// A quasi-deprecated helper used in rustdoc and save-analysis to get
332 /// the type from a HIR node.
333 pub fn hir_ty_to_ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, hir_ty: &hir::Ty) -> Ty<'tcx> {
334 // In case there are any projections etc, find the "environment"
335 // def-id that will be used to determine the traits/predicates in
336 // scope. This is derived from the enclosing item-like thing.
337 let env_node_id = tcx.hir.get_parent(hir_ty.id);
338 let env_def_id = tcx.hir.local_def_id(env_node_id);
339 let item_cx = self::collect::ItemCtxt::new(tcx, env_def_id);
340 item_cx.to_ty(hir_ty)
343 __build_diagnostic_array! { librustc_typeck, DIAGNOSTICS }