]> git.lizzy.rs Git - rust.git/blob - src/librustc_typeck/lib.rs
Rollup merge of #57295 - d-e-s-o:topic/be-be, r=zackmdavis
[rust.git] / src / librustc_typeck / lib.rs
1 /*!
2
3 # typeck.rs
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_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/")]
61
62 #![allow(non_camel_case_types)]
63
64 #![feature(box_patterns)]
65 #![feature(box_syntax)]
66 #![feature(crate_visibility_modifier)]
67 #![feature(exhaustive_patterns)]
68 #![feature(nll)]
69 #![feature(quote)]
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)]
75
76 #![recursion_limit="256"]
77
78 #[macro_use] extern crate log;
79 #[macro_use] extern crate syntax;
80 extern crate syntax_pos;
81
82 extern crate arena;
83
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;
90
91 // N.B., this module needs to be declared first so diagnostics are
92 // registered before they are used.
93 mod diagnostics;
94
95 mod astconv;
96 mod check;
97 mod check_unused;
98 mod coherence;
99 mod collect;
100 mod constrained_type_params;
101 mod structured_errors;
102 mod impl_wf_check;
103 mod namespace;
104 mod outlives;
105 mod variance;
106
107 use hir::Node;
108 use rustc_target::spec::abi::Abi;
109 use rustc::hir;
110 use rustc::infer::InferOk;
111 use rustc::lint;
112 use rustc::middle;
113 use rustc::session;
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;
119 use rustc::util;
120 use rustc::util::profiling::ProfileCategory;
121 use session::{CompileIncomplete, config};
122 use syntax_pos::Span;
123 use syntax::ast;
124 use util::common::time;
125
126 use std::iter;
127
128 pub struct TypeAndSubsts<'tcx> {
129     substs: &'tcx Substs<'tcx>,
130     ty: Ty<'tcx>,
131 }
132
133 fn check_type_alias_enum_variants_enabled<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
134                                                           span: Span) {
135     if !tcx.features().type_alias_enum_variants {
136         let mut err = tcx.sess.struct_span_err(
137             span,
138             "enum variants on type aliases are experimental"
139         );
140         if nightly_options::is_nightly_build() {
141             help!(&mut err,
142                 "add `#![feature(type_alias_enum_variants)]` to the \
143                 crate attributes to enable");
144         }
145         err.emit();
146     }
147 }
148
149 fn require_c_abi_if_variadic(tcx: TyCtxt,
150                              decl: &hir::FnDecl,
151                              abi: Abi,
152                              span: Span) {
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();
157     }
158 }
159
160 fn require_same_types<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
161                                 cause: &ObligationCause<'tcx>,
162                                 expected: Ty<'tcx>,
163                                 actual: Ty<'tcx>)
164                                 -> bool {
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);
171             }
172             Err(err) => {
173                 infcx.report_mismatched_types(cause, expected, actual, err).emit();
174                 return false;
175             }
176         }
177
178         match fulfill_cx.select_all_or_error(infcx) {
179             Ok(()) => true,
180             Err(errors) => {
181                 infcx.report_fulfillment_errors(&errors, None, false);
182                 false
183             }
184         }
185     })
186 }
187
188 fn check_main_fn_ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
189                               main_id: ast::NodeId,
190                               main_span: Span) {
191     let main_def_id = tcx.hir().local_def_id(main_id);
192     let main_t = tcx.type_of(main_def_id);
193     match main_t.sty {
194         ty::FnDef(..) => {
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)
204                             .emit();
205                         error = true;
206                     }
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")
211                             .emit();
212                         error = true;
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(
231                 tcx.mk_fn_sig(
232                     iter::empty(),
233                     expected_return_type,
234                     false,
235                     hir::Unsafety::Normal,
236                     Abi::Rust
237                 )
238             ));
239
240             require_same_types(
241                 tcx,
242                 &ObligationCause::new(main_span, main_id, ObligationCauseCode::MainFunctionType),
243                 se_ty,
244                 tcx.mk_fn_ptr(actual));
245         }
246         _ => {
247             span_bug!(main_span,
248                       "main has a non-function type: found `{}`",
249                       main_t);
250         }
251     }
252 }
253
254 fn check_start_fn_ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
255                                start_id: ast::NodeId,
256                                start_span: Span) {
257     let start_def_id = tcx.hir().local_def_id(start_id);
258     let start_t = tcx.type_of(start_def_id);
259     match start_t.sty {
260         ty::FnDef(..) => {
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")
269                             .emit();
270                         error = true;
271                     }
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")
276                             .emit();
277                         error = true;
278                     }
279                     if error {
280                         return;
281                     }
282                 }
283             }
284
285             let se_ty = tcx.mk_fn_ptr(ty::Binder::bind(
286                 tcx.mk_fn_sig(
287                     [
288                         tcx.types.isize,
289                         tcx.mk_imm_ptr(tcx.mk_imm_ptr(tcx.types.u8))
290                     ].iter().cloned(),
291                     tcx.types.isize,
292                     false,
293                     hir::Unsafety::Normal,
294                     Abi::Rust
295                 )
296             ));
297
298             require_same_types(
299                 tcx,
300                 &ObligationCause::new(start_span, start_id, ObligationCauseCode::StartFunctionType),
301                 se_ty,
302                 tcx.mk_fn_ptr(tcx.fn_sig(start_def_id)));
303         }
304         _ => {
305             span_bug!(start_span,
306                       "start has a non-function type: found `{}`",
307                       start_t);
308         }
309     }
310 }
311
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() {
314         match entry_type {
315             config::EntryFnType::Main => check_main_fn_ty(tcx, id, sp),
316             config::EntryFnType::Start => check_start_fn_ty(tcx, id, sp),
317         }
318     }
319 }
320
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);
327 }
328
329 pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>)
330                              -> Result<(), CompileIncomplete>
331 {
332     tcx.sess.profiler(|p| p.start_activity(ProfileCategory::TypeChecking));
333
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));
339
340     })?;
341
342     tcx.sess.track_errors(|| {
343         time(tcx.sess, "outlives testing", ||
344             outlives::test::test_inferred_outlives(tcx));
345     })?;
346
347     tcx.sess.track_errors(|| {
348         time(tcx.sess, "impl wf inference", ||
349              impl_wf_check::impl_wf_check(tcx));
350     })?;
351
352     tcx.sess.track_errors(|| {
353       time(tcx.sess, "coherence checking", ||
354           coherence::check_coherence(tcx));
355     })?;
356
357     tcx.sess.track_errors(|| {
358         time(tcx.sess, "variance testing", ||
359              variance::test::test_variance(tcx));
360     })?;
361
362     time(tcx.sess, "wf checking", || check::check_wf_new(tcx))?;
363
364     time(tcx.sess, "item-types checking", || check::check_item_types(tcx))?;
365
366     time(tcx.sess, "item-bodies checking", || check::check_item_bodies(tcx))?;
367
368     check_unused::check_crate(tcx);
369     check_for_entry_fn(tcx);
370
371     tcx.sess.profiler(|p| p.end_activity(ProfileCategory::TypeChecking));
372
373     tcx.sess.compile_status()
374 }
375
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);
385
386     astconv::AstConv::ast_ty_to_ty(&item_cx, hir_ty)
387 }
388
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
400     );
401
402     (principal, projections)
403 }
404
405 __build_diagnostic_array! { librustc_typeck, DIAGNOSTICS }