]> git.lizzy.rs Git - rust.git/blob - src/librustc_typeck/lib.rs
Auto merge of #69550 - RalfJung:scalar, r=oli-obk
[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(try_blocks)]
66 #![feature(never_type)]
67 #![recursion_limit = "256"]
68
69 #[macro_use]
70 extern crate log;
71
72 #[macro_use]
73 extern crate rustc;
74
75 // This is used by Clippy.
76 pub mod expr_use_visitor;
77
78 mod astconv;
79 mod check;
80 mod check_unused;
81 mod coherence;
82 mod collect;
83 mod constrained_generic_params;
84 mod impl_wf_check;
85 mod mem_categorization;
86 mod outlives;
87 mod structured_errors;
88 mod variance;
89
90 use rustc::lint;
91 use rustc::middle;
92 use rustc::session;
93 use rustc::session::config::EntryFnType;
94 use rustc::ty::query::Providers;
95 use rustc::ty::subst::SubstsRef;
96 use rustc::ty::{self, Ty, TyCtxt};
97 use rustc::util;
98 use rustc::util::common::ErrorReported;
99 use rustc_errors::struct_span_err;
100 use rustc_hir as hir;
101 use rustc_hir::def_id::{DefId, LOCAL_CRATE};
102 use rustc_hir::Node;
103 use rustc_infer::infer::{InferOk, TyCtxtInferExt};
104 use rustc_infer::traits::{ObligationCause, ObligationCauseCode, TraitEngine, TraitEngineExt};
105 use rustc_span::{Span, DUMMY_SP};
106 use rustc_target::spec::abi::Abi;
107
108 use std::iter;
109
110 use astconv::{AstConv, Bounds};
111 pub struct TypeAndSubsts<'tcx> {
112     substs: SubstsRef<'tcx>,
113     ty: Ty<'tcx>,
114 }
115
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!(
119             tcx.sess,
120             span,
121             E0045,
122             "C-variadic function must have C or cdecl calling convention"
123         );
124         err.span_label(span, "C-variadics require C or cdecl calling convention").emit();
125     }
126 }
127
128 fn require_same_types<'tcx>(
129     tcx: TyCtxt<'tcx>,
130     cause: &ObligationCause<'tcx>,
131     expected: Ty<'tcx>,
132     actual: Ty<'tcx>,
133 ) -> bool {
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);
140             }
141             Err(err) => {
142                 infcx.report_mismatched_types(cause, expected, actual, err).emit();
143                 return false;
144             }
145         }
146
147         match fulfill_cx.select_all_or_error(infcx) {
148             Ok(()) => true,
149             Err(errors) => {
150                 infcx.report_fulfillment_errors(&errors, None, false);
151                 false
152             }
153         }
154     })
155 }
156
157 fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: DefId) {
158     let main_id = tcx.hir().as_local_hir_id(main_def_id).unwrap();
159     let main_span = tcx.def_span(main_def_id);
160     let main_t = tcx.type_of(main_def_id);
161     match main_t.kind {
162         ty::FnDef(..) => {
163             if let Some(Node::Item(it)) = tcx.hir().find(main_id) {
164                 if let hir::ItemKind::Fn(.., 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 \
168                                    parameters"
169                             .to_owned();
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)
173                             .emit();
174                         error = true;
175                     }
176                     if let Some(sp) = generics.where_clause.span() {
177                         struct_span_err!(
178                             tcx.sess,
179                             sp,
180                             E0646,
181                             "`main` function is not allowed to have a `where` clause"
182                         )
183                         .span_label(sp, "`main` cannot have a `where` clause")
184                         .emit();
185                         error = true;
186                     }
187                     if error {
188                         return;
189                     }
190                 }
191             }
192
193             let actual = tcx.fn_sig(main_def_id);
194             let expected_return_type = if tcx.lang_items().termination().is_some() {
195                 // we take the return type of the given main function, the real check is done
196                 // in `check_fn`
197                 actual.output().skip_binder()
198             } else {
199                 // standard () main return type
200                 tcx.mk_unit()
201             };
202
203             let se_ty = tcx.mk_fn_ptr(ty::Binder::bind(tcx.mk_fn_sig(
204                 iter::empty(),
205                 expected_return_type,
206                 false,
207                 hir::Unsafety::Normal,
208                 Abi::Rust,
209             )));
210
211             require_same_types(
212                 tcx,
213                 &ObligationCause::new(main_span, main_id, ObligationCauseCode::MainFunctionType),
214                 se_ty,
215                 tcx.mk_fn_ptr(actual),
216             );
217         }
218         _ => {
219             span_bug!(main_span, "main has a non-function type: found `{}`", main_t);
220         }
221     }
222 }
223
224 fn check_start_fn_ty(tcx: TyCtxt<'_>, start_def_id: DefId) {
225     let start_id = tcx.hir().as_local_hir_id(start_def_id).unwrap();
226     let start_span = tcx.def_span(start_def_id);
227     let start_t = tcx.type_of(start_def_id);
228     match start_t.kind {
229         ty::FnDef(..) => {
230             if let Some(Node::Item(it)) = tcx.hir().find(start_id) {
231                 if let hir::ItemKind::Fn(.., ref generics, _) = it.kind {
232                     let mut error = false;
233                     if !generics.params.is_empty() {
234                         struct_span_err!(
235                             tcx.sess,
236                             generics.span,
237                             E0132,
238                             "start function is not allowed to have type parameters"
239                         )
240                         .span_label(generics.span, "start function cannot have type parameters")
241                         .emit();
242                         error = true;
243                     }
244                     if let Some(sp) = generics.where_clause.span() {
245                         struct_span_err!(
246                             tcx.sess,
247                             sp,
248                             E0647,
249                             "start function is not allowed to have a `where` clause"
250                         )
251                         .span_label(sp, "start function cannot have a `where` clause")
252                         .emit();
253                         error = true;
254                     }
255                     if error {
256                         return;
257                     }
258                 }
259             }
260
261             let se_ty = tcx.mk_fn_ptr(ty::Binder::bind(tcx.mk_fn_sig(
262                 [tcx.types.isize, tcx.mk_imm_ptr(tcx.mk_imm_ptr(tcx.types.u8))].iter().cloned(),
263                 tcx.types.isize,
264                 false,
265                 hir::Unsafety::Normal,
266                 Abi::Rust,
267             )));
268
269             require_same_types(
270                 tcx,
271                 &ObligationCause::new(start_span, start_id, ObligationCauseCode::StartFunctionType),
272                 se_ty,
273                 tcx.mk_fn_ptr(tcx.fn_sig(start_def_id)),
274             );
275         }
276         _ => {
277             span_bug!(start_span, "start has a non-function type: found `{}`", start_t);
278         }
279     }
280 }
281
282 fn check_for_entry_fn(tcx: TyCtxt<'_>) {
283     match tcx.entry_fn(LOCAL_CRATE) {
284         Some((def_id, EntryFnType::Main)) => check_main_fn_ty(tcx, def_id),
285         Some((def_id, EntryFnType::Start)) => check_start_fn_ty(tcx, def_id),
286         _ => {}
287     }
288 }
289
290 pub fn provide(providers: &mut Providers<'_>) {
291     collect::provide(providers);
292     coherence::provide(providers);
293     check::provide(providers);
294     variance::provide(providers);
295     outlives::provide(providers);
296     impl_wf_check::provide(providers);
297 }
298
299 pub fn check_crate(tcx: TyCtxt<'_>) -> Result<(), ErrorReported> {
300     let _prof_timer = tcx.sess.timer("type_check_crate");
301
302     // this ensures that later parts of type checking can assume that items
303     // have valid types and not error
304     // FIXME(matthewjasper) We shouldn't need to do this.
305     tcx.sess.track_errors(|| {
306         tcx.sess.time("type_collecting", || {
307             for &module in tcx.hir().krate().modules.keys() {
308                 tcx.ensure().collect_mod_item_types(tcx.hir().local_def_id(module));
309             }
310         });
311     })?;
312
313     if tcx.features().rustc_attrs {
314         tcx.sess.track_errors(|| {
315             tcx.sess.time("outlives_testing", || outlives::test::test_inferred_outlives(tcx));
316         })?;
317     }
318
319     tcx.sess.track_errors(|| {
320         tcx.sess.time("impl_wf_inference", || impl_wf_check::impl_wf_check(tcx));
321     })?;
322
323     tcx.sess.track_errors(|| {
324         tcx.sess.time("coherence_checking", || coherence::check_coherence(tcx));
325     })?;
326
327     if tcx.features().rustc_attrs {
328         tcx.sess.track_errors(|| {
329             tcx.sess.time("variance_testing", || variance::test::test_variance(tcx));
330         })?;
331     }
332
333     tcx.sess.track_errors(|| {
334         tcx.sess.time("wf_checking", || check::check_wf_new(tcx));
335     })?;
336
337     tcx.sess.time("item_types_checking", || {
338         for &module in tcx.hir().krate().modules.keys() {
339             tcx.ensure().check_mod_item_types(tcx.hir().local_def_id(module));
340         }
341     });
342
343     tcx.sess.time("item_bodies_checking", || tcx.typeck_item_bodies(LOCAL_CRATE));
344
345     check_unused::check_crate(tcx);
346     check_for_entry_fn(tcx);
347
348     if tcx.sess.err_count() == 0 { Ok(()) } else { Err(ErrorReported) }
349 }
350
351 /// A quasi-deprecated helper used in rustdoc and clippy to get
352 /// the type from a HIR node.
353 pub fn hir_ty_to_ty<'tcx>(tcx: TyCtxt<'tcx>, hir_ty: &hir::Ty<'_>) -> Ty<'tcx> {
354     // In case there are any projections, etc., find the "environment"
355     // def-ID that will be used to determine the traits/predicates in
356     // scope.  This is derived from the enclosing item-like thing.
357     let env_node_id = tcx.hir().get_parent_item(hir_ty.hir_id);
358     let env_def_id = tcx.hir().local_def_id(env_node_id);
359     let item_cx = self::collect::ItemCtxt::new(tcx, env_def_id);
360
361     astconv::AstConv::ast_ty_to_ty(&item_cx, hir_ty)
362 }
363
364 pub fn hir_trait_to_predicates<'tcx>(
365     tcx: TyCtxt<'tcx>,
366     hir_trait: &hir::TraitRef<'_>,
367 ) -> Bounds<'tcx> {
368     // In case there are any projections, etc., find the "environment"
369     // def-ID that will be used to determine the traits/predicates in
370     // scope.  This is derived from the enclosing item-like thing.
371     let env_hir_id = tcx.hir().get_parent_item(hir_trait.hir_ref_id);
372     let env_def_id = tcx.hir().local_def_id(env_hir_id);
373     let item_cx = self::collect::ItemCtxt::new(tcx, env_def_id);
374     let mut bounds = Bounds::default();
375     let _ = AstConv::instantiate_poly_trait_ref_inner(
376         &item_cx,
377         hir_trait,
378         DUMMY_SP,
379         hir::Constness::NotConst,
380         tcx.types.err,
381         &mut bounds,
382         true,
383     );
384
385     bounds
386 }