5 The type checker is responsible for:
7 1. Determining the type of each expression.
8 2. Resolving methods and traits.
9 3. Guaranteeing that most type rules are met. ("Most?", you say, "why most?"
10 Well, dear reader, read on)
12 The main entry point is `check_crate()`. Type checking operates in
15 1. The collect phase first passes over all items and determines their
16 type, without examining their "innards".
18 2. Variance inference then runs to compute the variance of each parameter.
20 3. Coherence checks for overlapping or orphaned impls.
22 4. Finally, the check phase then checks function bodies and so forth.
23 Within the check phase, we check each function body one at a time
24 (bodies of function expressions are checked as part of the
25 containing function). Inference is used to supply types wherever
26 they are unknown. The actual checking of a function itself has
27 several phases (check, regionck, writeback), as discussed in the
28 documentation for the `check` module.
30 The type checker is defined into various submodules which are documented
33 - astconv: converts the AST representation of types
34 into the `ty` representation.
36 - collect: computes the types of each top-level item and enters them into
37 the `tcx.types` table for later use.
39 - coherence: enforces coherence rules, builds some tables.
41 - variance: variance inference
43 - outlives: outlives inference
45 - check: walks over function bodies and type checks them, inferring types for
46 local variables, type parameters, etc as necessary.
48 - infer: finds the types to use for each type variable such that
49 all subtyping and assignment constraints are met. In essence, the check
50 module specifies the constraints, and the infer module solves them.
54 This API is completely unstable and subject to change.
58 #![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
59 html_favicon_url = "https://doc.rust-lang.org/favicon.ico",
60 html_root_url = "https://doc.rust-lang.org/nightly/")]
62 #![allow(non_camel_case_types)]
64 #![feature(box_patterns)]
65 #![feature(box_syntax)]
66 #![feature(crate_visibility_modifier)]
67 #![feature(exhaustive_patterns)]
70 #![feature(refcell_replace_swap)]
71 #![feature(rustc_diagnostic_macros)]
72 #![feature(slice_patterns)]
73 #![feature(slice_sort_by_cached_key)]
74 #![feature(never_type)]
76 #![recursion_limit="256"]
78 #[macro_use] extern crate log;
79 #[macro_use] extern crate syntax;
80 extern crate syntax_pos;
84 #[macro_use] extern crate rustc;
85 extern crate rustc_platform_intrinsics as intrinsics;
86 extern crate rustc_data_structures;
87 extern crate rustc_errors as errors;
88 extern crate rustc_target;
89 extern crate smallvec;
91 // N.B., this module needs to be declared first so diagnostics are
92 // registered before they are used.
100 mod constrained_type_params;
101 mod structured_errors;
108 use rustc_target::spec::abi::Abi;
110 use rustc::infer::InferOk;
114 use rustc::session::config::nightly_options;
115 use rustc::traits::{ObligationCause, ObligationCauseCode, TraitEngine, TraitEngineExt};
116 use rustc::ty::subst::Substs;
117 use rustc::ty::{self, Ty, TyCtxt};
118 use rustc::ty::query::Providers;
120 use rustc::util::profiling::ProfileCategory;
121 use session::{CompileIncomplete, config};
122 use syntax_pos::Span;
124 use util::common::time;
128 pub struct TypeAndSubsts<'tcx> {
129 substs: &'tcx Substs<'tcx>,
133 fn check_type_alias_enum_variants_enabled<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
135 if !tcx.features().type_alias_enum_variants {
136 let mut err = tcx.sess.struct_span_err(
138 "enum variants on type aliases are experimental"
140 if nightly_options::is_nightly_build() {
142 "add `#![feature(type_alias_enum_variants)]` to the \
143 crate attributes to enable");
149 fn require_c_abi_if_variadic(tcx: TyCtxt,
153 if decl.variadic && !(abi == Abi::C || abi == Abi::Cdecl) {
154 let mut err = struct_span_err!(tcx.sess, span, E0045,
155 "variadic function must have C or cdecl calling convention");
156 err.span_label(span, "variadics require C or cdecl calling convention").emit();
160 fn require_same_types<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
161 cause: &ObligationCause<'tcx>,
165 tcx.infer_ctxt().enter(|ref infcx| {
166 let param_env = ty::ParamEnv::empty();
167 let mut fulfill_cx = TraitEngine::new(infcx.tcx);
168 match infcx.at(&cause, param_env).eq(expected, actual) {
169 Ok(InferOk { obligations, .. }) => {
170 fulfill_cx.register_predicate_obligations(infcx, obligations);
173 infcx.report_mismatched_types(cause, expected, actual, err).emit();
178 match fulfill_cx.select_all_or_error(infcx) {
181 infcx.report_fulfillment_errors(&errors, None, false);
188 fn check_main_fn_ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
189 main_id: ast::NodeId,
191 let main_def_id = tcx.hir().local_def_id(main_id);
192 let main_t = tcx.type_of(main_def_id);
195 if let Some(Node::Item(it)) = tcx.hir().find(main_id) {
196 if let hir::ItemKind::Fn(.., ref generics, _) = it.node {
197 let mut error = false;
198 if !generics.params.is_empty() {
199 let msg = "`main` function is not allowed to have generic \
200 parameters".to_owned();
201 let label = "`main` cannot have generic parameters".to_string();
202 struct_span_err!(tcx.sess, generics.span, E0131, "{}", msg)
203 .span_label(generics.span, label)
207 if let Some(sp) = generics.where_clause.span() {
208 struct_span_err!(tcx.sess, sp, E0646,
209 "`main` function is not allowed to have a `where` clause")
210 .span_label(sp, "`main` cannot have a `where` clause")
220 let actual = tcx.fn_sig(main_def_id);
221 let expected_return_type = if tcx.lang_items().termination().is_some() {
222 // we take the return type of the given main function, the real check is done
224 actual.output().skip_binder()
226 // standard () main return type
230 let se_ty = tcx.mk_fn_ptr(ty::Binder::bind(
233 expected_return_type,
235 hir::Unsafety::Normal,
242 &ObligationCause::new(main_span, main_id, ObligationCauseCode::MainFunctionType),
244 tcx.mk_fn_ptr(actual));
248 "main has a non-function type: found `{}`",
254 fn check_start_fn_ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
255 start_id: ast::NodeId,
257 let start_def_id = tcx.hir().local_def_id(start_id);
258 let start_t = tcx.type_of(start_def_id);
261 if let Some(Node::Item(it)) = tcx.hir().find(start_id) {
262 if let hir::ItemKind::Fn(.., ref generics, _) = it.node {
263 let mut error = false;
264 if !generics.params.is_empty() {
265 struct_span_err!(tcx.sess, generics.span, E0132,
266 "start function is not allowed to have type parameters")
267 .span_label(generics.span,
268 "start function cannot have type parameters")
272 if let Some(sp) = generics.where_clause.span() {
273 struct_span_err!(tcx.sess, sp, E0647,
274 "start function is not allowed to have a `where` clause")
275 .span_label(sp, "start function cannot have a `where` clause")
285 let se_ty = tcx.mk_fn_ptr(ty::Binder::bind(
289 tcx.mk_imm_ptr(tcx.mk_imm_ptr(tcx.types.u8))
293 hir::Unsafety::Normal,
300 &ObligationCause::new(start_span, start_id, ObligationCauseCode::StartFunctionType),
302 tcx.mk_fn_ptr(tcx.fn_sig(start_def_id)));
305 span_bug!(start_span,
306 "start has a non-function type: found `{}`",
312 fn check_for_entry_fn<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
313 if let Some((id, sp, entry_type)) = *tcx.sess.entry_fn.borrow() {
315 config::EntryFnType::Main => check_main_fn_ty(tcx, id, sp),
316 config::EntryFnType::Start => check_start_fn_ty(tcx, id, sp),
321 pub fn provide(providers: &mut Providers) {
322 collect::provide(providers);
323 coherence::provide(providers);
324 check::provide(providers);
325 variance::provide(providers);
326 outlives::provide(providers);
329 pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>)
330 -> Result<(), CompileIncomplete>
332 tcx.sess.profiler(|p| p.start_activity(ProfileCategory::TypeChecking));
334 // this ensures that later parts of type checking can assume that items
335 // have valid types and not error
336 tcx.sess.track_errors(|| {
337 time(tcx.sess, "type collecting", ||
338 collect::collect_item_types(tcx));
342 tcx.sess.track_errors(|| {
343 time(tcx.sess, "outlives testing", ||
344 outlives::test::test_inferred_outlives(tcx));
347 tcx.sess.track_errors(|| {
348 time(tcx.sess, "impl wf inference", ||
349 impl_wf_check::impl_wf_check(tcx));
352 tcx.sess.track_errors(|| {
353 time(tcx.sess, "coherence checking", ||
354 coherence::check_coherence(tcx));
357 tcx.sess.track_errors(|| {
358 time(tcx.sess, "variance testing", ||
359 variance::test::test_variance(tcx));
362 time(tcx.sess, "wf checking", || check::check_wf_new(tcx))?;
364 time(tcx.sess, "item-types checking", || check::check_item_types(tcx))?;
366 time(tcx.sess, "item-bodies checking", || check::check_item_bodies(tcx))?;
368 check_unused::check_crate(tcx);
369 check_for_entry_fn(tcx);
371 tcx.sess.profiler(|p| p.end_activity(ProfileCategory::TypeChecking));
373 tcx.sess.compile_status()
376 /// A quasi-deprecated helper used in rustdoc and save-analysis to get
377 /// the type from a HIR node.
378 pub fn hir_ty_to_ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, hir_ty: &hir::Ty) -> Ty<'tcx> {
379 // In case there are any projections etc, find the "environment"
380 // def-id that will be used to determine the traits/predicates in
381 // scope. This is derived from the enclosing item-like thing.
382 let env_node_id = tcx.hir().get_parent(hir_ty.id);
383 let env_def_id = tcx.hir().local_def_id(env_node_id);
384 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>, Span)>) {
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
402 (principal, projections)
405 __build_diagnostic_array! { librustc_typeck, DIAGNOSTICS }