]> git.lizzy.rs Git - rust.git/blob - src/librustc_typeck/lib.rs
pin docs: add some forward references
[rust.git] / src / librustc_typeck / lib.rs
1 /*!
2
3 # typeck
4
5 The type checker is responsible for:
6
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)
11
12 The main entry point is `check_crate()`. Type checking operates in
13 several major phases:
14
15 1. The collect phase first passes over all items and determines their
16    type, without examining their "innards".
17
18 2. Variance inference then runs to compute the variance of each parameter.
19
20 3. Coherence checks for overlapping or orphaned impls.
21
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.
29
30 The type checker is defined into various submodules which are documented
31 independently:
32
33 - astconv: converts the AST representation of types
34   into the `ty` representation.
35
36 - collect: computes the types of each top-level item and enters them into
37   the `tcx.types` table for later use.
38
39 - coherence: enforces coherence rules, builds some tables.
40
41 - variance: variance inference
42
43 - outlives: outlives inference
44
45 - check: walks over function bodies and type checks them, inferring types for
46   local variables, type parameters, etc as necessary.
47
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.
51
52 ## Note
53
54 This API is completely unstable and subject to change.
55
56 */
57
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)]
64 #![feature(nll)]
65 #![feature(or_patterns)]
66 #![feature(try_blocks)]
67 #![feature(never_type)]
68 #![feature(slice_partition_dedup)]
69 #![recursion_limit = "256"]
70
71 #[macro_use]
72 extern crate log;
73
74 #[macro_use]
75 extern crate rustc_middle;
76
77 // These are used by Clippy.
78 pub mod check;
79 pub mod expr_use_visitor;
80
81 mod astconv;
82 mod check_unused;
83 mod coherence;
84 mod collect;
85 mod constrained_generic_params;
86 mod impl_wf_check;
87 mod mem_categorization;
88 mod outlives;
89 mod structured_errors;
90 mod variance;
91
92 use rustc_errors::{struct_span_err, ErrorReported};
93 use rustc_hir as hir;
94 use rustc_hir::def_id::{LocalDefId, LOCAL_CRATE};
95 use rustc_hir::Node;
96 use rustc_infer::infer::{InferOk, TyCtxtInferExt};
97 use rustc_infer::traits::TraitEngineExt as _;
98 use rustc_middle::middle;
99 use rustc_middle::ty::query::Providers;
100 use rustc_middle::ty::{self, Ty, TyCtxt};
101 use rustc_middle::util;
102 use rustc_session::config::EntryFnType;
103 use rustc_span::{symbol::sym, Span, DUMMY_SP};
104 use rustc_target::spec::abi::Abi;
105 use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _;
106 use rustc_trait_selection::traits::{
107     ObligationCause, ObligationCauseCode, TraitEngine, TraitEngineExt as _,
108 };
109
110 use std::iter;
111
112 use astconv::{AstConv, Bounds};
113
114 fn require_c_abi_if_c_variadic(tcx: TyCtxt<'_>, decl: &hir::FnDecl<'_>, abi: Abi, span: Span) {
115     if decl.c_variadic && !(abi == Abi::C || abi == Abi::Cdecl) {
116         let mut err = struct_span_err!(
117             tcx.sess,
118             span,
119             E0045,
120             "C-variadic function must have C or cdecl calling convention"
121         );
122         err.span_label(span, "C-variadics require C or cdecl calling convention").emit();
123     }
124 }
125
126 fn require_same_types<'tcx>(
127     tcx: TyCtxt<'tcx>,
128     cause: &ObligationCause<'tcx>,
129     expected: Ty<'tcx>,
130     actual: Ty<'tcx>,
131 ) -> bool {
132     tcx.infer_ctxt().enter(|ref infcx| {
133         let param_env = ty::ParamEnv::empty();
134         let mut fulfill_cx = TraitEngine::new(infcx.tcx);
135         match infcx.at(&cause, param_env).eq(expected, actual) {
136             Ok(InferOk { obligations, .. }) => {
137                 fulfill_cx.register_predicate_obligations(infcx, obligations);
138             }
139             Err(err) => {
140                 infcx.report_mismatched_types(cause, expected, actual, err).emit();
141                 return false;
142             }
143         }
144
145         match fulfill_cx.select_all_or_error(infcx) {
146             Ok(()) => true,
147             Err(errors) => {
148                 infcx.report_fulfillment_errors(&errors, None, false);
149                 false
150             }
151         }
152     })
153 }
154
155 fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: LocalDefId) {
156     let main_id = tcx.hir().as_local_hir_id(main_def_id);
157     let main_span = tcx.def_span(main_def_id);
158     let main_t = tcx.type_of(main_def_id);
159     match main_t.kind {
160         ty::FnDef(..) => {
161             if let Some(Node::Item(it)) = tcx.hir().find(main_id) {
162                 if let hir::ItemKind::Fn(ref sig, ref generics, _) = it.kind {
163                     let mut error = false;
164                     if !generics.params.is_empty() {
165                         let msg = "`main` function is not allowed to have generic \
166                                    parameters"
167                             .to_owned();
168                         let label = "`main` cannot have generic parameters".to_string();
169                         struct_span_err!(tcx.sess, generics.span, E0131, "{}", msg)
170                             .span_label(generics.span, label)
171                             .emit();
172                         error = true;
173                     }
174                     if let Some(sp) = generics.where_clause.span() {
175                         struct_span_err!(
176                             tcx.sess,
177                             sp,
178                             E0646,
179                             "`main` function is not allowed to have a `where` clause"
180                         )
181                         .span_label(sp, "`main` cannot have a `where` clause")
182                         .emit();
183                         error = true;
184                     }
185                     if let hir::IsAsync::Async = sig.header.asyncness {
186                         let span = tcx.sess.source_map().guess_head_span(it.span);
187                         struct_span_err!(
188                             tcx.sess,
189                             span,
190                             E0752,
191                             "`main` function is not allowed to be `async`"
192                         )
193                         .span_label(span, "`main` function is not allowed to be `async`")
194                         .emit();
195                         error = true;
196                     }
197
198                     for attr in it.attrs {
199                         if tcx.sess.check_name(attr, sym::track_caller) {
200                             tcx.sess
201                                 .struct_span_err(
202                                     attr.span,
203                                     "`main` function is not allowed to be `#[track_caller]`",
204                                 )
205                                 .span_label(
206                                     main_span,
207                                     "`main` function is not allowed to be `#[track_caller]`",
208                                 )
209                                 .emit();
210                             error = true;
211                         }
212                     }
213
214                     if error {
215                         return;
216                     }
217                 }
218             }
219
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
223                 // in `check_fn`
224                 actual.output().skip_binder()
225             } else {
226                 // standard () main return type
227                 tcx.mk_unit()
228             };
229
230             let se_ty = tcx.mk_fn_ptr(ty::Binder::bind(tcx.mk_fn_sig(
231                 iter::empty(),
232                 expected_return_type,
233                 false,
234                 hir::Unsafety::Normal,
235                 Abi::Rust,
236             )));
237
238             require_same_types(
239                 tcx,
240                 &ObligationCause::new(main_span, main_id, ObligationCauseCode::MainFunctionType),
241                 se_ty,
242                 tcx.mk_fn_ptr(actual),
243             );
244         }
245         _ => {
246             span_bug!(main_span, "main has a non-function type: found `{}`", main_t);
247         }
248     }
249 }
250
251 fn check_start_fn_ty(tcx: TyCtxt<'_>, start_def_id: LocalDefId) {
252     let start_id = tcx.hir().as_local_hir_id(start_def_id);
253     let start_span = tcx.def_span(start_def_id);
254     let start_t = tcx.type_of(start_def_id);
255     match start_t.kind {
256         ty::FnDef(..) => {
257             if let Some(Node::Item(it)) = tcx.hir().find(start_id) {
258                 if let hir::ItemKind::Fn(ref sig, ref generics, _) = it.kind {
259                     let mut error = false;
260                     if !generics.params.is_empty() {
261                         struct_span_err!(
262                             tcx.sess,
263                             generics.span,
264                             E0132,
265                             "start function is not allowed to have type parameters"
266                         )
267                         .span_label(generics.span, "start function cannot have type parameters")
268                         .emit();
269                         error = true;
270                     }
271                     if let Some(sp) = generics.where_clause.span() {
272                         struct_span_err!(
273                             tcx.sess,
274                             sp,
275                             E0647,
276                             "start function is not allowed to have a `where` clause"
277                         )
278                         .span_label(sp, "start function cannot have a `where` clause")
279                         .emit();
280                         error = true;
281                     }
282                     if let hir::IsAsync::Async = sig.header.asyncness {
283                         let span = tcx.sess.source_map().guess_head_span(it.span);
284                         struct_span_err!(
285                             tcx.sess,
286                             span,
287                             E0752,
288                             "`start` is not allowed to be `async`"
289                         )
290                         .span_label(span, "`start` is not allowed to be `async`")
291                         .emit();
292                         error = true;
293                     }
294
295                     for attr in it.attrs {
296                         if tcx.sess.check_name(attr, sym::track_caller) {
297                             tcx.sess
298                                 .struct_span_err(
299                                     attr.span,
300                                     "`start` is not allowed to be `#[track_caller]`",
301                                 )
302                                 .span_label(
303                                     start_span,
304                                     "`start` is not allowed to be `#[track_caller]`",
305                                 )
306                                 .emit();
307                             error = true;
308                         }
309                     }
310
311                     if error {
312                         return;
313                     }
314                 }
315             }
316
317             let se_ty = tcx.mk_fn_ptr(ty::Binder::bind(tcx.mk_fn_sig(
318                 [tcx.types.isize, tcx.mk_imm_ptr(tcx.mk_imm_ptr(tcx.types.u8))].iter().cloned(),
319                 tcx.types.isize,
320                 false,
321                 hir::Unsafety::Normal,
322                 Abi::Rust,
323             )));
324
325             require_same_types(
326                 tcx,
327                 &ObligationCause::new(start_span, start_id, ObligationCauseCode::StartFunctionType),
328                 se_ty,
329                 tcx.mk_fn_ptr(tcx.fn_sig(start_def_id)),
330             );
331         }
332         _ => {
333             span_bug!(start_span, "start has a non-function type: found `{}`", start_t);
334         }
335     }
336 }
337
338 fn check_for_entry_fn(tcx: TyCtxt<'_>) {
339     match tcx.entry_fn(LOCAL_CRATE) {
340         Some((def_id, EntryFnType::Main)) => check_main_fn_ty(tcx, def_id),
341         Some((def_id, EntryFnType::Start)) => check_start_fn_ty(tcx, def_id),
342         _ => {}
343     }
344 }
345
346 pub fn provide(providers: &mut Providers) {
347     collect::provide(providers);
348     coherence::provide(providers);
349     check::provide(providers);
350     variance::provide(providers);
351     outlives::provide(providers);
352     impl_wf_check::provide(providers);
353 }
354
355 pub fn check_crate(tcx: TyCtxt<'_>) -> Result<(), ErrorReported> {
356     let _prof_timer = tcx.sess.timer("type_check_crate");
357
358     // this ensures that later parts of type checking can assume that items
359     // have valid types and not error
360     // FIXME(matthewjasper) We shouldn't need to do this.
361     tcx.sess.track_errors(|| {
362         tcx.sess.time("type_collecting", || {
363             for &module in tcx.hir().krate().modules.keys() {
364                 tcx.ensure().collect_mod_item_types(tcx.hir().local_def_id(module));
365             }
366         });
367     })?;
368
369     if tcx.features().rustc_attrs {
370         tcx.sess.track_errors(|| {
371             tcx.sess.time("outlives_testing", || outlives::test::test_inferred_outlives(tcx));
372         })?;
373     }
374
375     tcx.sess.track_errors(|| {
376         tcx.sess.time("impl_wf_inference", || impl_wf_check::impl_wf_check(tcx));
377     })?;
378
379     tcx.sess.track_errors(|| {
380         tcx.sess.time("coherence_checking", || coherence::check_coherence(tcx));
381     })?;
382
383     if tcx.features().rustc_attrs {
384         tcx.sess.track_errors(|| {
385             tcx.sess.time("variance_testing", || variance::test::test_variance(tcx));
386         })?;
387     }
388
389     tcx.sess.track_errors(|| {
390         tcx.sess.time("wf_checking", || check::check_wf_new(tcx));
391     })?;
392
393     // NOTE: This is copy/pasted in librustdoc/core.rs and should be kept in sync.
394     tcx.sess.time("item_types_checking", || {
395         for &module in tcx.hir().krate().modules.keys() {
396             tcx.ensure().check_mod_item_types(tcx.hir().local_def_id(module));
397         }
398     });
399
400     tcx.sess.time("item_bodies_checking", || tcx.typeck_item_bodies(LOCAL_CRATE));
401
402     check_unused::check_crate(tcx);
403     check_for_entry_fn(tcx);
404
405     if tcx.sess.err_count() == 0 { Ok(()) } else { Err(ErrorReported) }
406 }
407
408 /// A quasi-deprecated helper used in rustdoc and clippy to get
409 /// the type from a HIR node.
410 pub fn hir_ty_to_ty<'tcx>(tcx: TyCtxt<'tcx>, hir_ty: &hir::Ty<'_>) -> Ty<'tcx> {
411     // In case there are any projections, etc., find the "environment"
412     // def-ID that will be used to determine the traits/predicates in
413     // scope.  This is derived from the enclosing item-like thing.
414     let env_node_id = tcx.hir().get_parent_item(hir_ty.hir_id);
415     let env_def_id = tcx.hir().local_def_id(env_node_id);
416     let item_cx = self::collect::ItemCtxt::new(tcx, env_def_id.to_def_id());
417
418     astconv::AstConv::ast_ty_to_ty(&item_cx, hir_ty)
419 }
420
421 pub fn hir_trait_to_predicates<'tcx>(
422     tcx: TyCtxt<'tcx>,
423     hir_trait: &hir::TraitRef<'_>,
424     self_ty: Ty<'tcx>,
425 ) -> Bounds<'tcx> {
426     // In case there are any projections, etc., find the "environment"
427     // def-ID that will be used to determine the traits/predicates in
428     // scope.  This is derived from the enclosing item-like thing.
429     let env_hir_id = tcx.hir().get_parent_item(hir_trait.hir_ref_id);
430     let env_def_id = tcx.hir().local_def_id(env_hir_id);
431     let item_cx = self::collect::ItemCtxt::new(tcx, env_def_id.to_def_id());
432     let mut bounds = Bounds::default();
433     let _ = AstConv::instantiate_poly_trait_ref_inner(
434         &item_cx,
435         hir_trait,
436         DUMMY_SP,
437         hir::Constness::NotConst,
438         self_ty,
439         &mut bounds,
440         true,
441     );
442
443     bounds
444 }