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 - outlives: outlives inference
55 - check: walks over function bodies and type checks them, inferring types for
56 local variables, type parameters, etc as necessary.
58 - infer: finds the types to use for each type variable such that
59 all subtyping and assignment constraints are met. In essence, the check
60 module specifies the constraints, and the infer module solves them.
64 This API is completely unstable and subject to change.
68 #![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
69 html_favicon_url = "https://doc.rust-lang.org/favicon.ico",
70 html_root_url = "https://doc.rust-lang.org/nightly/")]
72 #![allow(non_camel_case_types)]
74 #![feature(box_patterns)]
75 #![feature(box_syntax)]
76 #![feature(crate_visibility_modifier)]
78 #![feature(exhaustive_patterns)]
79 #![feature(iterator_find_map)]
81 #![feature(refcell_replace_swap)]
82 #![feature(rustc_diagnostic_macros)]
83 #![feature(slice_patterns)]
84 #![feature(slice_sort_by_cached_key)]
85 #![feature(never_type)]
87 #![recursion_limit="256"]
89 #[macro_use] extern crate log;
90 #[macro_use] extern crate syntax;
91 extern crate syntax_pos;
94 #[macro_use] extern crate rustc;
95 extern crate rustc_platform_intrinsics as intrinsics;
96 extern crate rustc_data_structures;
97 extern crate rustc_errors as errors;
98 extern crate rustc_target;
106 use hir::map as hir_map;
107 use rustc::infer::InferOk;
108 use rustc::ty::subst::Substs;
109 use rustc::ty::{self, Ty, TyCtxt};
110 use rustc::ty::query::Providers;
111 use rustc::traits::{ObligationCause, ObligationCauseCode, TraitEngine, TraitEngineExt};
112 use session::{CompileIncomplete, config};
113 use util::common::time;
116 use rustc_target::spec::abi::Abi;
117 use syntax_pos::Span;
121 // NB: This module needs to be declared first so diagnostics are
122 // registered before they are used.
130 mod constrained_type_params;
131 mod structured_errors;
137 pub struct TypeAndSubsts<'tcx> {
138 substs: &'tcx Substs<'tcx>,
142 fn require_c_abi_if_variadic(tcx: TyCtxt,
146 if decl.variadic && !(abi == Abi::C || abi == Abi::Cdecl) {
147 let mut err = struct_span_err!(tcx.sess, span, E0045,
148 "variadic function must have C or cdecl calling convention");
149 err.span_label(span, "variadics require C or cdecl calling convention").emit();
153 fn require_same_types<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
154 cause: &ObligationCause<'tcx>,
158 tcx.infer_ctxt().enter(|ref infcx| {
159 let param_env = ty::ParamEnv::empty();
160 let mut fulfill_cx = TraitEngine::new(infcx.tcx);
161 match infcx.at(&cause, param_env).eq(expected, actual) {
162 Ok(InferOk { obligations, .. }) => {
163 fulfill_cx.register_predicate_obligations(infcx, obligations);
166 infcx.report_mismatched_types(cause, expected, actual, err).emit();
171 match fulfill_cx.select_all_or_error(infcx) {
174 infcx.report_fulfillment_errors(&errors, None, false);
181 fn check_main_fn_ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
182 main_id: ast::NodeId,
184 let main_def_id = tcx.hir.local_def_id(main_id);
185 let main_t = tcx.type_of(main_def_id);
188 match tcx.hir.find(main_id) {
189 Some(hir_map::NodeItem(it)) => {
191 hir::ItemKind::Fn(.., ref generics, _) => {
192 let mut error = false;
193 if !generics.params.is_empty() {
194 let msg = "`main` function is not allowed to have generic \
195 parameters".to_string();
196 let label = "`main` cannot have generic parameters".to_string();
197 struct_span_err!(tcx.sess, generics.span, E0131, "{}", msg)
198 .span_label(generics.span, label)
202 if let Some(sp) = generics.where_clause.span() {
203 struct_span_err!(tcx.sess, sp, E0646,
204 "`main` function is not allowed to have a `where` clause")
205 .span_label(sp, "`main` cannot have a `where` clause")
219 let actual = tcx.fn_sig(main_def_id);
220 let expected_return_type = if tcx.lang_items().termination().is_some() {
221 // we take the return type of the given main function, the real check is done
223 actual.output().skip_binder()
225 // standard () main return type
229 let se_ty = tcx.mk_fn_ptr(ty::Binder::bind(
232 expected_return_type,
234 hir::Unsafety::Normal,
241 &ObligationCause::new(main_span, main_id, ObligationCauseCode::MainFunctionType),
243 tcx.mk_fn_ptr(actual));
247 "main has a non-function type: found `{}`",
253 fn check_start_fn_ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
254 start_id: ast::NodeId,
256 let start_def_id = tcx.hir.local_def_id(start_id);
257 let start_t = tcx.type_of(start_def_id);
260 match tcx.hir.find(start_id) {
261 Some(hir_map::NodeItem(it)) => {
263 hir::ItemKind::Fn(.., ref generics, _) => {
264 let mut error = false;
265 if !generics.params.is_empty() {
266 struct_span_err!(tcx.sess, generics.span, E0132,
267 "start function is not allowed to have type parameters")
268 .span_label(generics.span,
269 "start function cannot have type parameters")
273 if let Some(sp) = generics.where_clause.span() {
274 struct_span_err!(tcx.sess, sp, E0647,
275 "start function is not allowed to have a `where` clause")
276 .span_label(sp, "start function cannot have a `where` clause")
290 let se_ty = tcx.mk_fn_ptr(ty::Binder::bind(
294 tcx.mk_imm_ptr(tcx.mk_imm_ptr(tcx.types.u8))
298 hir::Unsafety::Normal,
305 &ObligationCause::new(start_span, start_id, ObligationCauseCode::StartFunctionType),
307 tcx.mk_fn_ptr(tcx.fn_sig(start_def_id)));
310 span_bug!(start_span,
311 "start has a non-function type: found `{}`",
317 fn check_for_entry_fn<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
318 if let Some((id, sp, entry_type)) = *tcx.sess.entry_fn.borrow() {
320 config::EntryMain => check_main_fn_ty(tcx, id, sp),
321 config::EntryStart => check_start_fn_ty(tcx, id, sp),
326 pub fn provide(providers: &mut Providers) {
327 collect::provide(providers);
328 coherence::provide(providers);
329 check::provide(providers);
330 variance::provide(providers);
331 outlives::provide(providers);
334 pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>)
335 -> Result<(), CompileIncomplete>
337 // this ensures that later parts of type checking can assume that items
338 // have valid types and not error
339 tcx.sess.track_errors(|| {
340 time(tcx.sess, "type collecting", ||
341 collect::collect_item_types(tcx));
345 tcx.sess.track_errors(|| {
346 time(tcx.sess, "outlives testing", ||
347 outlives::test::test_inferred_outlives(tcx));
350 tcx.sess.track_errors(|| {
351 time(tcx.sess, "impl wf inference", ||
352 impl_wf_check::impl_wf_check(tcx));
355 tcx.sess.track_errors(|| {
356 time(tcx.sess, "coherence checking", ||
357 coherence::check_coherence(tcx));
360 tcx.sess.track_errors(|| {
361 time(tcx.sess, "variance testing", ||
362 variance::test::test_variance(tcx));
365 time(tcx.sess, "wf checking", || check::check_wf_new(tcx))?;
367 time(tcx.sess, "item-types checking", || check::check_item_types(tcx))?;
369 time(tcx.sess, "item-bodies checking", || check::check_item_bodies(tcx))?;
371 check_unused::check_crate(tcx);
372 check_for_entry_fn(tcx);
374 tcx.sess.compile_status()
377 /// A quasi-deprecated helper used in rustdoc and save-analysis to get
378 /// the type from a HIR node.
379 pub fn hir_ty_to_ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, hir_ty: &hir::Ty) -> Ty<'tcx> {
380 // In case there are any projections etc, find the "environment"
381 // def-id that will be used to determine the traits/predicates in
382 // scope. This is derived from the enclosing item-like thing.
383 let env_node_id = tcx.hir.get_parent(hir_ty.id);
384 let env_def_id = tcx.hir.local_def_id(env_node_id);
385 let item_cx = self::collect::ItemCtxt::new(tcx, env_def_id);
386 astconv::AstConv::ast_ty_to_ty(&item_cx, hir_ty)
389 pub fn hir_trait_to_predicates<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, hir_trait: &hir::TraitRef)
390 -> (ty::PolyTraitRef<'tcx>, Vec<ty::PolyProjectionPredicate<'tcx>>) {
391 // In case there are any projections etc, find the "environment"
392 // def-id that will be used to determine the traits/predicates in
393 // scope. This is derived from the enclosing item-like thing.
394 let env_node_id = tcx.hir.get_parent(hir_trait.ref_id);
395 let env_def_id = tcx.hir.local_def_id(env_node_id);
396 let item_cx = self::collect::ItemCtxt::new(tcx, env_def_id);
397 let mut projections = Vec::new();
398 let principal = astconv::AstConv::instantiate_poly_trait_ref_inner(
399 &item_cx, hir_trait, tcx.types.err, &mut projections, true
401 (principal, projections)
404 __build_diagnostic_array! { librustc_typeck, DIAGNOSTICS }