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)]
77 #![feature(exhaustive_patterns)]
80 #![feature(refcell_replace_swap)]
81 #![feature(rustc_diagnostic_macros)]
82 #![feature(slice_patterns)]
83 #![feature(slice_sort_by_cached_key)]
84 #![feature(never_type)]
86 #![recursion_limit="256"]
88 #[macro_use] extern crate log;
89 #[macro_use] extern crate syntax;
90 extern crate syntax_pos;
93 #[macro_use] extern crate rustc;
94 extern crate rustc_platform_intrinsics as intrinsics;
95 extern crate rustc_data_structures;
96 extern crate rustc_errors as errors;
97 extern crate rustc_target;
98 extern crate smallvec;
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 rustc::util::profiling::ProfileCategory;
113 use session::{CompileIncomplete, config};
114 use util::common::time;
117 use rustc_target::spec::abi::Abi;
118 use syntax_pos::Span;
122 // NB: This module needs to be declared first so diagnostics are
123 // registered before they are used.
131 mod constrained_type_params;
132 mod structured_errors;
138 pub struct TypeAndSubsts<'tcx> {
139 substs: &'tcx Substs<'tcx>,
143 fn require_c_abi_if_variadic(tcx: TyCtxt,
147 if decl.variadic && !(abi == Abi::C || abi == Abi::Cdecl) {
148 let mut err = struct_span_err!(tcx.sess, span, E0045,
149 "variadic function must have C or cdecl calling convention");
150 err.span_label(span, "variadics require C or cdecl calling convention").emit();
154 fn require_same_types<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
155 cause: &ObligationCause<'tcx>,
159 tcx.infer_ctxt().enter(|ref infcx| {
160 let param_env = ty::ParamEnv::empty();
161 let mut fulfill_cx = TraitEngine::new(infcx.tcx);
162 match infcx.at(&cause, param_env).eq(expected, actual) {
163 Ok(InferOk { obligations, .. }) => {
164 fulfill_cx.register_predicate_obligations(infcx, obligations);
167 infcx.report_mismatched_types(cause, expected, actual, err).emit();
172 match fulfill_cx.select_all_or_error(infcx) {
175 infcx.report_fulfillment_errors(&errors, None, false);
182 fn check_main_fn_ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
183 main_id: ast::NodeId,
185 let main_def_id = tcx.hir().local_def_id(main_id);
186 let main_t = tcx.type_of(main_def_id);
189 if let Some(Node::Item(it)) = tcx.hir().find(main_id) {
190 if let hir::ItemKind::Fn(.., ref generics, _) = it.node {
191 let mut error = false;
192 if !generics.params.is_empty() {
193 let msg = "`main` function is not allowed to have generic \
194 parameters".to_owned();
195 let label = "`main` cannot have generic parameters".to_string();
196 struct_span_err!(tcx.sess, generics.span, E0131, "{}", msg)
197 .span_label(generics.span, label)
201 if let Some(sp) = generics.where_clause.span() {
202 struct_span_err!(tcx.sess, sp, E0646,
203 "`main` function is not allowed to have a `where` clause")
204 .span_label(sp, "`main` cannot have a `where` clause")
214 let actual = tcx.fn_sig(main_def_id);
215 let expected_return_type = if tcx.lang_items().termination().is_some() {
216 // we take the return type of the given main function, the real check is done
218 actual.output().skip_binder()
220 // standard () main return type
224 let se_ty = tcx.mk_fn_ptr(ty::Binder::bind(
227 expected_return_type,
229 hir::Unsafety::Normal,
236 &ObligationCause::new(main_span, main_id, ObligationCauseCode::MainFunctionType),
238 tcx.mk_fn_ptr(actual));
242 "main has a non-function type: found `{}`",
248 fn check_start_fn_ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
249 start_id: ast::NodeId,
251 let start_def_id = tcx.hir().local_def_id(start_id);
252 let start_t = tcx.type_of(start_def_id);
255 if let Some(Node::Item(it)) = tcx.hir().find(start_id) {
256 if let hir::ItemKind::Fn(.., ref generics, _) = it.node {
257 let mut error = false;
258 if !generics.params.is_empty() {
259 struct_span_err!(tcx.sess, generics.span, E0132,
260 "start function is not allowed to have type parameters")
261 .span_label(generics.span,
262 "start function cannot have type parameters")
266 if let Some(sp) = generics.where_clause.span() {
267 struct_span_err!(tcx.sess, sp, E0647,
268 "start function is not allowed to have a `where` clause")
269 .span_label(sp, "start function cannot have a `where` clause")
279 let se_ty = tcx.mk_fn_ptr(ty::Binder::bind(
283 tcx.mk_imm_ptr(tcx.mk_imm_ptr(tcx.types.u8))
287 hir::Unsafety::Normal,
294 &ObligationCause::new(start_span, start_id, ObligationCauseCode::StartFunctionType),
296 tcx.mk_fn_ptr(tcx.fn_sig(start_def_id)));
299 span_bug!(start_span,
300 "start has a non-function type: found `{}`",
306 fn check_for_entry_fn<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
307 if let Some((id, sp, entry_type)) = *tcx.sess.entry_fn.borrow() {
309 config::EntryFnType::Main => check_main_fn_ty(tcx, id, sp),
310 config::EntryFnType::Start => check_start_fn_ty(tcx, id, sp),
315 pub fn provide(providers: &mut Providers) {
316 collect::provide(providers);
317 coherence::provide(providers);
318 check::provide(providers);
319 variance::provide(providers);
320 outlives::provide(providers);
323 pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>)
324 -> Result<(), CompileIncomplete>
326 tcx.sess.profiler(|p| p.start_activity(ProfileCategory::TypeChecking));
328 // this ensures that later parts of type checking can assume that items
329 // have valid types and not error
330 tcx.sess.track_errors(|| {
331 time(tcx.sess, "type collecting", ||
332 collect::collect_item_types(tcx));
336 tcx.sess.track_errors(|| {
337 time(tcx.sess, "outlives testing", ||
338 outlives::test::test_inferred_outlives(tcx));
341 tcx.sess.track_errors(|| {
342 time(tcx.sess, "impl wf inference", ||
343 impl_wf_check::impl_wf_check(tcx));
346 tcx.sess.track_errors(|| {
347 time(tcx.sess, "coherence checking", ||
348 coherence::check_coherence(tcx));
351 tcx.sess.track_errors(|| {
352 time(tcx.sess, "variance testing", ||
353 variance::test::test_variance(tcx));
356 time(tcx.sess, "wf checking", || check::check_wf_new(tcx))?;
358 time(tcx.sess, "item-types checking", || check::check_item_types(tcx))?;
360 time(tcx.sess, "item-bodies checking", || check::check_item_bodies(tcx))?;
362 check_unused::check_crate(tcx);
363 check_for_entry_fn(tcx);
365 tcx.sess.profiler(|p| p.end_activity(ProfileCategory::TypeChecking));
367 tcx.sess.compile_status()
370 /// A quasi-deprecated helper used in rustdoc and save-analysis to get
371 /// the type from a HIR node.
372 pub fn hir_ty_to_ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, hir_ty: &hir::Ty) -> Ty<'tcx> {
373 // In case there are any projections etc, find the "environment"
374 // def-id that will be used to determine the traits/predicates in
375 // scope. This is derived from the enclosing item-like thing.
376 let env_node_id = tcx.hir().get_parent(hir_ty.id);
377 let env_def_id = tcx.hir().local_def_id(env_node_id);
378 let item_cx = self::collect::ItemCtxt::new(tcx, env_def_id);
380 astconv::AstConv::ast_ty_to_ty(&item_cx, hir_ty)
383 pub fn hir_trait_to_predicates<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, hir_trait: &hir::TraitRef)
384 -> (ty::PolyTraitRef<'tcx>, Vec<(ty::PolyProjectionPredicate<'tcx>, Span)>) {
385 // In case there are any projections etc, find the "environment"
386 // def-id that will be used to determine the traits/predicates in
387 // scope. This is derived from the enclosing item-like thing.
388 let env_node_id = tcx.hir().get_parent(hir_trait.ref_id);
389 let env_def_id = tcx.hir().local_def_id(env_node_id);
390 let item_cx = self::collect::ItemCtxt::new(tcx, env_def_id);
391 let mut projections = Vec::new();
392 let (principal, _) = astconv::AstConv::instantiate_poly_trait_ref_inner(
393 &item_cx, hir_trait, tcx.types.err, &mut projections, true
396 (principal, projections)
399 __build_diagnostic_array! { librustc_typeck, DIAGNOSTICS }