]> git.proxmox.com Git - rustc.git/blob - src/librustc_typeck/lib.rs
Imported Upstream version 1.6.0+dfsg1
[rustc.git] / src / librustc_typeck / lib.rs
1 // Copyright 2014 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 /*!
12
13 typeck.rs, an introduction
14
15 The type checker is responsible for:
16
17 1. Determining the type of each expression
18 2. Resolving methods and traits
19 3. Guaranteeing that most type rules are met ("most?", you say, "why most?"
20 Well, dear reader, read on)
21
22 The main entry point is `check_crate()`. Type checking operates in
23 several major phases:
24
25 1. The collect phase first passes over all items and determines their
26 type, without examining their "innards".
27
28 2. Variance inference then runs to compute the variance of each parameter
29
30 3. Coherence checks for overlapping or orphaned impls
31
32 4. Finally, the check phase then checks function bodies and so forth.
33 Within the check phase, we check each function body one at a time
34 (bodies of function expressions are checked as part of the
35 containing function). Inference is used to supply types wherever
36 they are unknown. The actual checking of a function itself has
37 several phases (check, regionck, writeback), as discussed in the
38 documentation for the `check` module.
39
40 The type checker is defined into various submodules which are documented
41 independently:
42
43 - astconv: converts the AST representation of types
44 into the `ty` representation
45
46 - collect: computes the types of each top-level item and enters them into
47 the `cx.tcache` table for later use
48
49 - coherence: enforces coherence rules, builds some tables
50
51 - variance: variance inference
52
53 - check: walks over function bodies and type checks them, inferring types for
54 local variables, type parameters, etc as necessary.
55
56 - infer: finds the types to use for each type variable such that
57 all subtyping and assignment constraints are met. In essence, the check
58 module specifies the constraints, and the infer module solves them.
59
60 # Note
61
62 This API is completely unstable and subject to change.
63
64 */
65 // Do not remove on snapshot creation. Needed for bootstrap. (Issue #22364)
66 #![cfg_attr(stage0, feature(custom_attribute))]
67 #![crate_name = "rustc_typeck"]
68 #![unstable(feature = "rustc_private", issue = "27812")]
69 #![cfg_attr(stage0, staged_api)]
70 #![crate_type = "dylib"]
71 #![crate_type = "rlib"]
72 #![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
73 html_favicon_url = "https://doc.rust-lang.org/favicon.ico",
74 html_root_url = "https://doc.rust-lang.org/nightly/")]
75
76 #![allow(non_camel_case_types)]
77
78 #![feature(box_patterns)]
79 #![feature(box_syntax)]
80 #![feature(iter_arith)]
81 #![feature(quote)]
82 #![feature(rustc_diagnostic_macros)]
83 #![feature(rustc_private)]
84 #![feature(staged_api)]
85 #![feature(cell_extras)]
86
87 #[macro_use] extern crate log;
88 #[macro_use] extern crate syntax;
89
90 extern crate arena;
91 extern crate fmt_macros;
92 extern crate rustc;
93 extern crate rustc_platform_intrinsics as intrinsics;
94 extern crate rustc_front;
95 extern crate rustc_back;
96
97 pub use rustc::front;
98 pub use rustc::lint;
99 pub use rustc::middle;
100 pub use rustc::session;
101 pub use rustc::util;
102
103 use front::map as hir_map;
104 use middle::def;
105 use middle::infer::{self, TypeOrigin};
106 use middle::subst;
107 use middle::ty::{self, Ty, HasTypeFlags};
108 use session::config;
109 use util::common::time;
110 use rustc_front::hir;
111
112 use syntax::codemap::Span;
113 use syntax::print::pprust::*;
114 use syntax::{ast, abi};
115
116 use std::cell::RefCell;
117
118 // NB: This module needs to be declared first so diagnostics are
119 // registered before they are used.
120 pub mod diagnostics;
121
122 pub mod check;
123 mod rscope;
124 mod astconv;
125 pub mod collect;
126 mod constrained_type_params;
127 pub mod coherence;
128 pub mod variance;
129
130 pub struct TypeAndSubsts<'tcx> {
131 pub substs: subst::Substs<'tcx>,
132 pub ty: Ty<'tcx>,
133 }
134
135 pub struct CrateCtxt<'a, 'tcx: 'a> {
136 // A mapping from method call sites to traits that have that method.
137 pub trait_map: ty::TraitMap,
138 /// A vector of every trait accessible in the whole crate
139 /// (i.e. including those from subcrates). This is used only for
140 /// error reporting, and so is lazily initialised and generally
141 /// shouldn't taint the common path (hence the RefCell).
142 pub all_traits: RefCell<Option<check::method::AllTraitsVec>>,
143 pub tcx: &'a ty::ctxt<'tcx>,
144 }
145
146 // Functions that write types into the node type table
147 fn write_ty_to_tcx<'tcx>(tcx: &ty::ctxt<'tcx>, node_id: ast::NodeId, ty: Ty<'tcx>) {
148 debug!("write_ty_to_tcx({}, {:?})", node_id, ty);
149 assert!(!ty.needs_infer());
150 tcx.node_type_insert(node_id, ty);
151 }
152
153 fn write_substs_to_tcx<'tcx>(tcx: &ty::ctxt<'tcx>,
154 node_id: ast::NodeId,
155 item_substs: ty::ItemSubsts<'tcx>) {
156 if !item_substs.is_noop() {
157 debug!("write_substs_to_tcx({}, {:?})",
158 node_id,
159 item_substs);
160
161 assert!(!item_substs.substs.types.needs_infer());
162
163 tcx.tables.borrow_mut().item_substs.insert(node_id, item_substs);
164 }
165 }
166
167 fn lookup_full_def(tcx: &ty::ctxt, sp: Span, id: ast::NodeId) -> def::Def {
168 match tcx.def_map.borrow().get(&id) {
169 Some(x) => x.full_def(),
170 None => {
171 span_fatal!(tcx.sess, sp, E0242, "internal error looking up a definition")
172 }
173 }
174 }
175
176 fn require_c_abi_if_variadic(tcx: &ty::ctxt,
177 decl: &hir::FnDecl,
178 abi: abi::Abi,
179 span: Span) {
180 if decl.variadic && abi != abi::C {
181 span_err!(tcx.sess, span, E0045,
182 "variadic function must have C calling convention");
183 }
184 }
185
186 fn require_same_types<'a, 'tcx, M>(tcx: &ty::ctxt<'tcx>,
187 maybe_infcx: Option<&infer::InferCtxt<'a, 'tcx>>,
188 t1_is_expected: bool,
189 span: Span,
190 t1: Ty<'tcx>,
191 t2: Ty<'tcx>,
192 msg: M)
193 -> bool where
194 M: FnOnce() -> String,
195 {
196 let result = match maybe_infcx {
197 None => {
198 let infcx = infer::new_infer_ctxt(tcx, &tcx.tables, None, false);
199 infer::mk_eqty(&infcx, t1_is_expected, TypeOrigin::Misc(span), t1, t2)
200 }
201 Some(infcx) => {
202 infer::mk_eqty(infcx, t1_is_expected, TypeOrigin::Misc(span), t1, t2)
203 }
204 };
205
206 match result {
207 Ok(_) => true,
208 Err(ref terr) => {
209 span_err!(tcx.sess, span, E0211, "{}: {}", msg(), terr);
210 tcx.note_and_explain_type_err(terr, span);
211 false
212 }
213 }
214 }
215
216 fn check_main_fn_ty(ccx: &CrateCtxt,
217 main_id: ast::NodeId,
218 main_span: Span) {
219 let tcx = ccx.tcx;
220 let main_t = tcx.node_id_to_type(main_id);
221 match main_t.sty {
222 ty::TyBareFn(..) => {
223 match tcx.map.find(main_id) {
224 Some(hir_map::NodeItem(it)) => {
225 match it.node {
226 hir::ItemFn(_, _, _, _, ref ps, _)
227 if ps.is_parameterized() => {
228 span_err!(ccx.tcx.sess, main_span, E0131,
229 "main function is not allowed to have type parameters");
230 return;
231 }
232 _ => ()
233 }
234 }
235 _ => ()
236 }
237 let main_def_id = tcx.map.local_def_id(main_id);
238 let se_ty = tcx.mk_fn(Some(main_def_id), tcx.mk_bare_fn(ty::BareFnTy {
239 unsafety: hir::Unsafety::Normal,
240 abi: abi::Rust,
241 sig: ty::Binder(ty::FnSig {
242 inputs: Vec::new(),
243 output: ty::FnConverging(tcx.mk_nil()),
244 variadic: false
245 })
246 }));
247
248 require_same_types(tcx, None, false, main_span, main_t, se_ty,
249 || {
250 format!("main function expects type: `{}`",
251 se_ty)
252 });
253 }
254 _ => {
255 tcx.sess.span_bug(main_span,
256 &format!("main has a non-function type: found `{}`",
257 main_t));
258 }
259 }
260 }
261
262 fn check_start_fn_ty(ccx: &CrateCtxt,
263 start_id: ast::NodeId,
264 start_span: Span) {
265 let tcx = ccx.tcx;
266 let start_t = tcx.node_id_to_type(start_id);
267 match start_t.sty {
268 ty::TyBareFn(..) => {
269 match tcx.map.find(start_id) {
270 Some(hir_map::NodeItem(it)) => {
271 match it.node {
272 hir::ItemFn(_,_,_,_,ref ps,_)
273 if ps.is_parameterized() => {
274 span_err!(tcx.sess, start_span, E0132,
275 "start function is not allowed to have type parameters");
276 return;
277 }
278 _ => ()
279 }
280 }
281 _ => ()
282 }
283
284 let se_ty = tcx.mk_fn(Some(ccx.tcx.map.local_def_id(start_id)),
285 tcx.mk_bare_fn(ty::BareFnTy {
286 unsafety: hir::Unsafety::Normal,
287 abi: abi::Rust,
288 sig: ty::Binder(ty::FnSig {
289 inputs: vec!(
290 tcx.types.isize,
291 tcx.mk_imm_ptr(tcx.mk_imm_ptr(tcx.types.u8))
292 ),
293 output: ty::FnConverging(tcx.types.isize),
294 variadic: false,
295 }),
296 }));
297
298 require_same_types(tcx, None, false, start_span, start_t, se_ty,
299 || {
300 format!("start function expects type: `{}`",
301 se_ty)
302 });
303
304 }
305 _ => {
306 tcx.sess.span_bug(start_span,
307 &format!("start has a non-function type: found `{}`",
308 start_t));
309 }
310 }
311 }
312
313 fn check_for_entry_fn(ccx: &CrateCtxt) {
314 let tcx = ccx.tcx;
315 match *tcx.sess.entry_fn.borrow() {
316 Some((id, sp)) => match tcx.sess.entry_type.get() {
317 Some(config::EntryMain) => check_main_fn_ty(ccx, id, sp),
318 Some(config::EntryStart) => check_start_fn_ty(ccx, id, sp),
319 Some(config::EntryNone) => {}
320 None => tcx.sess.bug("entry function without a type")
321 },
322 None => {}
323 }
324 }
325
326 pub fn check_crate(tcx: &ty::ctxt, trait_map: ty::TraitMap) {
327 let time_passes = tcx.sess.time_passes();
328 let ccx = CrateCtxt {
329 trait_map: trait_map,
330 all_traits: RefCell::new(None),
331 tcx: tcx
332 };
333
334 time(time_passes, "type collecting", ||
335 collect::collect_item_types(tcx));
336
337 // this ensures that later parts of type checking can assume that items
338 // have valid types and not error
339 tcx.sess.abort_if_errors();
340
341 time(time_passes, "variance inference", ||
342 variance::infer_variance(tcx));
343
344 time(time_passes, "coherence checking", ||
345 coherence::check_coherence(&ccx));
346
347 time(time_passes, "wf checking (old)", ||
348 check::check_wf_old(&ccx));
349
350 time(time_passes, "item-types checking", ||
351 check::check_item_types(&ccx));
352
353 time(time_passes, "item-bodies checking", ||
354 check::check_item_bodies(&ccx));
355
356 time(time_passes, "drop-impl checking", ||
357 check::check_drop_impls(&ccx));
358
359 // Do this last so that if there are errors in the old code, they
360 // get reported, and we don't get extra warnings.
361 time(time_passes, "wf checking (new)", ||
362 check::check_wf_new(&ccx));
363
364 check_for_entry_fn(&ccx);
365 tcx.sess.abort_if_errors();
366 }
367
368 __build_diagnostic_array! { librustc_typeck, DIAGNOSTICS }