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_root_url = "https://doc.rust-lang.org/nightly/")]
59 #![allow(non_camel_case_types)]
60 #![feature(bool_to_option)]
61 #![feature(box_syntax)]
62 #![feature(crate_visibility_modifier)]
63 #![feature(in_band_lifetimes)]
65 #![feature(or_patterns)]
66 #![feature(try_blocks)]
67 #![feature(never_type)]
68 #![feature(slice_partition_dedup)]
69 #![recursion_limit = "256"]
75 extern crate rustc_middle;
77 // These are used by Clippy.
79 pub mod expr_use_visitor;
86 mod constrained_generic_params;
88 mod mem_categorization;
90 mod structured_errors;
93 use rustc_errors::{struct_span_err, ErrorReported};
95 use rustc_hir::def_id::{LocalDefId, LOCAL_CRATE};
97 use rustc_infer::infer::{InferOk, TyCtxtInferExt};
98 use rustc_infer::traits::TraitEngineExt as _;
99 use rustc_middle::middle;
100 use rustc_middle::ty::query::Providers;
101 use rustc_middle::ty::{self, Ty, TyCtxt};
102 use rustc_middle::util;
103 use rustc_session::config::EntryFnType;
104 use rustc_span::{symbol::sym, Span, DUMMY_SP};
105 use rustc_target::spec::abi::Abi;
106 use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _;
107 use rustc_trait_selection::traits::{
108 ObligationCause, ObligationCauseCode, TraitEngine, TraitEngineExt as _,
113 use astconv::AstConv;
116 fn require_c_abi_if_c_variadic(tcx: TyCtxt<'_>, decl: &hir::FnDecl<'_>, abi: Abi, span: Span) {
117 if decl.c_variadic && !(abi == Abi::C || abi == Abi::Cdecl) {
118 let mut err = struct_span_err!(
122 "C-variadic function must have C or cdecl calling convention"
124 err.span_label(span, "C-variadics require C or cdecl calling convention").emit();
128 fn require_same_types<'tcx>(
130 cause: &ObligationCause<'tcx>,
134 tcx.infer_ctxt().enter(|ref infcx| {
135 let param_env = ty::ParamEnv::empty();
136 let mut fulfill_cx = TraitEngine::new(infcx.tcx);
137 match infcx.at(&cause, param_env).eq(expected, actual) {
138 Ok(InferOk { obligations, .. }) => {
139 fulfill_cx.register_predicate_obligations(infcx, obligations);
142 infcx.report_mismatched_types(cause, expected, actual, err).emit();
147 match fulfill_cx.select_all_or_error(infcx) {
150 infcx.report_fulfillment_errors(&errors, None, false);
157 fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: LocalDefId) {
158 let main_id = tcx.hir().local_def_id_to_hir_id(main_def_id);
159 let main_span = tcx.def_span(main_def_id);
160 let main_t = tcx.type_of(main_def_id);
163 if let Some(Node::Item(it)) = tcx.hir().find(main_id) {
164 if let hir::ItemKind::Fn(ref sig, ref generics, _) = it.kind {
165 let mut error = false;
166 if !generics.params.is_empty() {
167 let msg = "`main` function is not allowed to have generic \
170 let label = "`main` cannot have generic parameters".to_string();
171 struct_span_err!(tcx.sess, generics.span, E0131, "{}", msg)
172 .span_label(generics.span, label)
176 if let Some(sp) = generics.where_clause.span() {
181 "`main` function is not allowed to have a `where` clause"
183 .span_label(sp, "`main` cannot have a `where` clause")
187 if let hir::IsAsync::Async = sig.header.asyncness {
188 let span = tcx.sess.source_map().guess_head_span(it.span);
193 "`main` function is not allowed to be `async`"
195 .span_label(span, "`main` function is not allowed to be `async`")
200 for attr in it.attrs {
201 if tcx.sess.check_name(attr, sym::track_caller) {
205 "`main` function is not allowed to be `#[track_caller]`",
209 "`main` function is not allowed to be `#[track_caller]`",
222 let actual = tcx.fn_sig(main_def_id);
223 let expected_return_type = if tcx.lang_items().termination().is_some() {
224 // we take the return type of the given main function, the real check is done
226 actual.output().skip_binder()
228 // standard () main return type
232 let se_ty = tcx.mk_fn_ptr(ty::Binder::bind(tcx.mk_fn_sig(
234 expected_return_type,
236 hir::Unsafety::Normal,
242 &ObligationCause::new(main_span, main_id, ObligationCauseCode::MainFunctionType),
244 tcx.mk_fn_ptr(actual),
248 span_bug!(main_span, "main has a non-function type: found `{}`", main_t);
253 fn check_start_fn_ty(tcx: TyCtxt<'_>, start_def_id: LocalDefId) {
254 let start_id = tcx.hir().local_def_id_to_hir_id(start_def_id);
255 let start_span = tcx.def_span(start_def_id);
256 let start_t = tcx.type_of(start_def_id);
259 if let Some(Node::Item(it)) = tcx.hir().find(start_id) {
260 if let hir::ItemKind::Fn(ref sig, ref generics, _) = it.kind {
261 let mut error = false;
262 if !generics.params.is_empty() {
267 "start function is not allowed to have type parameters"
269 .span_label(generics.span, "start function cannot have type parameters")
273 if let Some(sp) = generics.where_clause.span() {
278 "start function is not allowed to have a `where` clause"
280 .span_label(sp, "start function cannot have a `where` clause")
284 if let hir::IsAsync::Async = sig.header.asyncness {
285 let span = tcx.sess.source_map().guess_head_span(it.span);
290 "`start` is not allowed to be `async`"
292 .span_label(span, "`start` is not allowed to be `async`")
297 for attr in it.attrs {
298 if tcx.sess.check_name(attr, sym::track_caller) {
302 "`start` is not allowed to be `#[track_caller]`",
306 "`start` is not allowed to be `#[track_caller]`",
319 let se_ty = tcx.mk_fn_ptr(ty::Binder::bind(tcx.mk_fn_sig(
320 [tcx.types.isize, tcx.mk_imm_ptr(tcx.mk_imm_ptr(tcx.types.u8))].iter().cloned(),
323 hir::Unsafety::Normal,
329 &ObligationCause::new(start_span, start_id, ObligationCauseCode::StartFunctionType),
331 tcx.mk_fn_ptr(tcx.fn_sig(start_def_id)),
335 span_bug!(start_span, "start has a non-function type: found `{}`", start_t);
340 fn check_for_entry_fn(tcx: TyCtxt<'_>) {
341 match tcx.entry_fn(LOCAL_CRATE) {
342 Some((def_id, EntryFnType::Main)) => check_main_fn_ty(tcx, def_id),
343 Some((def_id, EntryFnType::Start)) => check_start_fn_ty(tcx, def_id),
348 pub fn provide(providers: &mut Providers) {
349 collect::provide(providers);
350 coherence::provide(providers);
351 check::provide(providers);
352 variance::provide(providers);
353 outlives::provide(providers);
354 impl_wf_check::provide(providers);
357 pub fn check_crate(tcx: TyCtxt<'_>) -> Result<(), ErrorReported> {
358 let _prof_timer = tcx.sess.timer("type_check_crate");
360 // this ensures that later parts of type checking can assume that items
361 // have valid types and not error
362 // FIXME(matthewjasper) We shouldn't need to do this.
363 tcx.sess.track_errors(|| {
364 tcx.sess.time("type_collecting", || {
365 for &module in tcx.hir().krate().modules.keys() {
366 tcx.ensure().collect_mod_item_types(tcx.hir().local_def_id(module));
371 if tcx.features().rustc_attrs {
372 tcx.sess.track_errors(|| {
373 tcx.sess.time("outlives_testing", || outlives::test::test_inferred_outlives(tcx));
377 tcx.sess.track_errors(|| {
378 tcx.sess.time("impl_wf_inference", || impl_wf_check::impl_wf_check(tcx));
381 tcx.sess.track_errors(|| {
382 tcx.sess.time("coherence_checking", || coherence::check_coherence(tcx));
385 if tcx.features().rustc_attrs {
386 tcx.sess.track_errors(|| {
387 tcx.sess.time("variance_testing", || variance::test::test_variance(tcx));
391 tcx.sess.track_errors(|| {
392 tcx.sess.time("wf_checking", || check::check_wf_new(tcx));
395 // NOTE: This is copy/pasted in librustdoc/core.rs and should be kept in sync.
396 tcx.sess.time("item_types_checking", || {
397 for &module in tcx.hir().krate().modules.keys() {
398 tcx.ensure().check_mod_item_types(tcx.hir().local_def_id(module));
402 tcx.sess.time("item_bodies_checking", || tcx.typeck_item_bodies(LOCAL_CRATE));
404 check_unused::check_crate(tcx);
405 check_for_entry_fn(tcx);
407 if tcx.sess.err_count() == 0 { Ok(()) } else { Err(ErrorReported) }
410 /// A quasi-deprecated helper used in rustdoc and clippy to get
411 /// the type from a HIR node.
412 pub fn hir_ty_to_ty<'tcx>(tcx: TyCtxt<'tcx>, hir_ty: &hir::Ty<'_>) -> Ty<'tcx> {
413 // In case there are any projections, etc., find the "environment"
414 // def-ID that will be used to determine the traits/predicates in
415 // scope. This is derived from the enclosing item-like thing.
416 let env_node_id = tcx.hir().get_parent_item(hir_ty.hir_id);
417 let env_def_id = tcx.hir().local_def_id(env_node_id);
418 let item_cx = self::collect::ItemCtxt::new(tcx, env_def_id.to_def_id());
420 astconv::AstConv::ast_ty_to_ty(&item_cx, hir_ty)
423 pub fn hir_trait_to_predicates<'tcx>(
425 hir_trait: &hir::TraitRef<'_>,
428 // In case there are any projections, etc., find the "environment"
429 // def-ID that will be used to determine the traits/predicates in
430 // scope. This is derived from the enclosing item-like thing.
431 let env_hir_id = tcx.hir().get_parent_item(hir_trait.hir_ref_id);
432 let env_def_id = tcx.hir().local_def_id(env_hir_id);
433 let item_cx = self::collect::ItemCtxt::new(tcx, env_def_id.to_def_id());
434 let mut bounds = Bounds::default();
435 let _ = AstConv::instantiate_poly_trait_ref_inner(
439 hir::Constness::NotConst,