]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_hir_typeck/src/lib.rs
ef089237994b618a3a92101a4942726c432e92e4
[rust.git] / compiler / rustc_hir_typeck / src / lib.rs
1 #![feature(if_let_guard)]
2 #![feature(let_chains)]
3 #![feature(try_blocks)]
4 #![feature(never_type)]
5 #![feature(min_specialization)]
6 #![feature(spec_option_partial_eq)]
7 #![feature(control_flow_enum)]
8 #![feature(drain_filter)]
9 #![allow(rustc::potential_query_instability)]
10 #![recursion_limit = "256"]
11
12 #[macro_use]
13 extern crate tracing;
14
15 #[macro_use]
16 extern crate rustc_middle;
17
18 mod _match;
19 mod autoderef;
20 mod callee;
21 // Used by clippy;
22 pub mod cast;
23 mod check;
24 mod closure;
25 mod coercion;
26 mod demand;
27 mod diverges;
28 mod errors;
29 mod expectation;
30 mod expr;
31 // Used by clippy;
32 pub mod expr_use_visitor;
33 mod fallback;
34 mod fn_ctxt;
35 mod gather_locals;
36 mod generator_interior;
37 mod inherited;
38 mod intrinsicck;
39 mod mem_categorization;
40 mod method;
41 mod op;
42 mod pat;
43 mod place_op;
44 mod rvalue_scopes;
45 mod upvar;
46 mod writeback;
47
48 pub use diverges::Diverges;
49 pub use expectation::Expectation;
50 pub use fn_ctxt::*;
51 pub use inherited::{Inherited, InheritedBuilder};
52
53 use crate::check::check_fn;
54 use crate::coercion::DynamicCoerceMany;
55 use crate::gather_locals::GatherLocalsVisitor;
56 use rustc_data_structures::unord::UnordSet;
57 use rustc_errors::{struct_span_err, MultiSpan};
58 use rustc_hir as hir;
59 use rustc_hir::def::Res;
60 use rustc_hir::intravisit::Visitor;
61 use rustc_hir::{HirIdMap, Node};
62 use rustc_hir_analysis::astconv::AstConv;
63 use rustc_hir_analysis::check::check_abi;
64 use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
65 use rustc_middle::traits;
66 use rustc_middle::ty::query::Providers;
67 use rustc_middle::ty::{self, Ty, TyCtxt};
68 use rustc_session::config;
69 use rustc_session::Session;
70 use rustc_span::def_id::{DefId, LocalDefId};
71 use rustc_span::Span;
72
73 #[macro_export]
74 macro_rules! type_error_struct {
75     ($session:expr, $span:expr, $typ:expr, $code:ident, $($message:tt)*) => ({
76         let mut err = rustc_errors::struct_span_err!($session, $span, $code, $($message)*);
77
78         if $typ.references_error() {
79             err.downgrade_to_delayed_bug();
80         }
81
82         err
83     })
84 }
85
86 /// The type of a local binding, including the revealed type for anon types.
87 #[derive(Copy, Clone, Debug)]
88 pub struct LocalTy<'tcx> {
89     decl_ty: Ty<'tcx>,
90     revealed_ty: Ty<'tcx>,
91 }
92
93 #[derive(Copy, Clone)]
94 pub struct UnsafetyState {
95     pub def: hir::HirId,
96     pub unsafety: hir::Unsafety,
97     from_fn: bool,
98 }
99
100 impl UnsafetyState {
101     pub fn function(unsafety: hir::Unsafety, def: hir::HirId) -> UnsafetyState {
102         UnsafetyState { def, unsafety, from_fn: true }
103     }
104
105     pub fn recurse(self, blk: &hir::Block<'_>) -> UnsafetyState {
106         use hir::BlockCheckMode;
107         match self.unsafety {
108             // If this unsafe, then if the outer function was already marked as
109             // unsafe we shouldn't attribute the unsafe'ness to the block. This
110             // way the block can be warned about instead of ignoring this
111             // extraneous block (functions are never warned about).
112             hir::Unsafety::Unsafe if self.from_fn => self,
113
114             unsafety => {
115                 let (unsafety, def) = match blk.rules {
116                     BlockCheckMode::UnsafeBlock(..) => (hir::Unsafety::Unsafe, blk.hir_id),
117                     BlockCheckMode::DefaultBlock => (unsafety, self.def),
118                 };
119                 UnsafetyState { def, unsafety, from_fn: false }
120             }
121         }
122     }
123 }
124
125 /// If this `DefId` is a "primary tables entry", returns
126 /// `Some((body_id, body_ty, fn_sig))`. Otherwise, returns `None`.
127 ///
128 /// If this function returns `Some`, then `typeck_results(def_id)` will
129 /// succeed; if it returns `None`, then `typeck_results(def_id)` may or
130 /// may not succeed. In some cases where this function returns `None`
131 /// (notably closures), `typeck_results(def_id)` would wind up
132 /// redirecting to the owning function.
133 fn primary_body_of(
134     tcx: TyCtxt<'_>,
135     id: hir::HirId,
136 ) -> Option<(hir::BodyId, Option<&hir::Ty<'_>>, Option<&hir::FnSig<'_>>)> {
137     match tcx.hir().get(id) {
138         Node::Item(item) => match item.kind {
139             hir::ItemKind::Const(ty, body) | hir::ItemKind::Static(ty, _, body) => {
140                 Some((body, Some(ty), None))
141             }
142             hir::ItemKind::Fn(ref sig, .., body) => Some((body, None, Some(sig))),
143             _ => None,
144         },
145         Node::TraitItem(item) => match item.kind {
146             hir::TraitItemKind::Const(ty, Some(body)) => Some((body, Some(ty), None)),
147             hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Provided(body)) => {
148                 Some((body, None, Some(sig)))
149             }
150             _ => None,
151         },
152         Node::ImplItem(item) => match item.kind {
153             hir::ImplItemKind::Const(ty, body) => Some((body, Some(ty), None)),
154             hir::ImplItemKind::Fn(ref sig, body) => Some((body, None, Some(sig))),
155             _ => None,
156         },
157         Node::AnonConst(constant) => Some((constant.body, None, None)),
158         _ => None,
159     }
160 }
161
162 fn has_typeck_results(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
163     // Closures' typeck results come from their outermost function,
164     // as they are part of the same "inference environment".
165     let typeck_root_def_id = tcx.typeck_root_def_id(def_id);
166     if typeck_root_def_id != def_id {
167         return tcx.has_typeck_results(typeck_root_def_id);
168     }
169
170     if let Some(def_id) = def_id.as_local() {
171         let id = tcx.hir().local_def_id_to_hir_id(def_id);
172         primary_body_of(tcx, id).is_some()
173     } else {
174         false
175     }
176 }
177
178 fn used_trait_imports(tcx: TyCtxt<'_>, def_id: LocalDefId) -> &UnordSet<LocalDefId> {
179     &*tcx.typeck(def_id).used_trait_imports
180 }
181
182 fn typeck_item_bodies(tcx: TyCtxt<'_>, (): ()) {
183     tcx.hir().par_body_owners(|body_owner_def_id| tcx.ensure().typeck(body_owner_def_id));
184 }
185
186 fn typeck_const_arg<'tcx>(
187     tcx: TyCtxt<'tcx>,
188     (did, param_did): (LocalDefId, DefId),
189 ) -> &ty::TypeckResults<'tcx> {
190     let fallback = move || tcx.type_of(param_did);
191     typeck_with_fallback(tcx, did, fallback)
192 }
193
194 fn typeck<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &ty::TypeckResults<'tcx> {
195     if let Some(param_did) = tcx.opt_const_param_of(def_id) {
196         tcx.typeck_const_arg((def_id, param_did))
197     } else {
198         let fallback = move || tcx.type_of(def_id.to_def_id());
199         typeck_with_fallback(tcx, def_id, fallback)
200     }
201 }
202
203 /// Used only to get `TypeckResults` for type inference during error recovery.
204 /// Currently only used for type inference of `static`s and `const`s to avoid type cycle errors.
205 fn diagnostic_only_typeck<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &ty::TypeckResults<'tcx> {
206     let fallback = move || {
207         let span = tcx.hir().span(tcx.hir().local_def_id_to_hir_id(def_id));
208         tcx.ty_error_with_message(span, "diagnostic only typeck table used")
209     };
210     typeck_with_fallback(tcx, def_id, fallback)
211 }
212
213 fn typeck_with_fallback<'tcx>(
214     tcx: TyCtxt<'tcx>,
215     def_id: LocalDefId,
216     fallback: impl Fn() -> Ty<'tcx> + 'tcx,
217 ) -> &'tcx ty::TypeckResults<'tcx> {
218     // Closures' typeck results come from their outermost function,
219     // as they are part of the same "inference environment".
220     let typeck_root_def_id = tcx.typeck_root_def_id(def_id.to_def_id()).expect_local();
221     if typeck_root_def_id != def_id {
222         return tcx.typeck(typeck_root_def_id);
223     }
224
225     let id = tcx.hir().local_def_id_to_hir_id(def_id);
226     let span = tcx.hir().span(id);
227
228     // Figure out what primary body this item has.
229     let (body_id, body_ty, fn_sig) = primary_body_of(tcx, id).unwrap_or_else(|| {
230         span_bug!(span, "can't type-check body of {:?}", def_id);
231     });
232     let body = tcx.hir().body(body_id);
233
234     let typeck_results = Inherited::build(tcx, def_id).enter(|inh| {
235         let param_env = tcx.param_env(def_id);
236         let mut fcx = if let Some(hir::FnSig { header, decl, .. }) = fn_sig {
237             let fn_sig = if rustc_hir_analysis::collect::get_infer_ret_ty(&decl.output).is_some() {
238                 let fcx = FnCtxt::new(&inh, param_env, body.value.hir_id);
239                 <dyn AstConv<'_>>::ty_of_fn(&fcx, id, header.unsafety, header.abi, decl, None, None)
240             } else {
241                 tcx.fn_sig(def_id)
242             };
243
244             check_abi(tcx, id, span, fn_sig.abi());
245
246             // Compute the function signature from point of view of inside the fn.
247             let fn_sig = tcx.liberate_late_bound_regions(def_id.to_def_id(), fn_sig);
248             let fn_sig = inh.normalize_associated_types_in(
249                 body.value.span,
250                 body_id.hir_id,
251                 param_env,
252                 fn_sig,
253             );
254             check_fn(&inh, param_env, fn_sig, decl, id, body, None, true).0
255         } else {
256             let fcx = FnCtxt::new(&inh, param_env, body.value.hir_id);
257             let expected_type = body_ty
258                 .and_then(|ty| match ty.kind {
259                     hir::TyKind::Infer => Some(<dyn AstConv<'_>>::ast_ty_to_ty(&fcx, ty)),
260                     _ => None,
261                 })
262                 .unwrap_or_else(|| match tcx.hir().get(id) {
263                     Node::AnonConst(_) => match tcx.hir().get(tcx.hir().get_parent_node(id)) {
264                         Node::Expr(&hir::Expr {
265                             kind: hir::ExprKind::ConstBlock(ref anon_const),
266                             ..
267                         }) if anon_const.hir_id == id => fcx.next_ty_var(TypeVariableOrigin {
268                             kind: TypeVariableOriginKind::TypeInference,
269                             span,
270                         }),
271                         Node::Ty(&hir::Ty {
272                             kind: hir::TyKind::Typeof(ref anon_const), ..
273                         }) if anon_const.hir_id == id => fcx.next_ty_var(TypeVariableOrigin {
274                             kind: TypeVariableOriginKind::TypeInference,
275                             span,
276                         }),
277                         Node::Expr(&hir::Expr { kind: hir::ExprKind::InlineAsm(asm), .. })
278                         | Node::Item(&hir::Item { kind: hir::ItemKind::GlobalAsm(asm), .. }) => {
279                             let operand_ty = asm
280                                 .operands
281                                 .iter()
282                                 .filter_map(|(op, _op_sp)| match op {
283                                     hir::InlineAsmOperand::Const { anon_const }
284                                         if anon_const.hir_id == id =>
285                                     {
286                                         // Inline assembly constants must be integers.
287                                         Some(fcx.next_int_var())
288                                     }
289                                     hir::InlineAsmOperand::SymFn { anon_const }
290                                         if anon_const.hir_id == id =>
291                                     {
292                                         Some(fcx.next_ty_var(TypeVariableOrigin {
293                                             kind: TypeVariableOriginKind::MiscVariable,
294                                             span,
295                                         }))
296                                     }
297                                     _ => None,
298                                 })
299                                 .next();
300                             operand_ty.unwrap_or_else(fallback)
301                         }
302                         _ => fallback(),
303                     },
304                     _ => fallback(),
305                 });
306
307             let expected_type = fcx.normalize_associated_types_in(body.value.span, expected_type);
308             fcx.require_type_is_sized(expected_type, body.value.span, traits::ConstSized);
309
310             // Gather locals in statics (because of block expressions).
311             GatherLocalsVisitor::new(&fcx).visit_body(body);
312
313             fcx.check_expr_coercable_to_type(&body.value, expected_type, None);
314
315             fcx.write_ty(id, expected_type);
316
317             fcx
318         };
319
320         let fallback_has_occurred = fcx.type_inference_fallback();
321
322         // Even though coercion casts provide type hints, we check casts after fallback for
323         // backwards compatibility. This makes fallback a stronger type hint than a cast coercion.
324         fcx.check_casts();
325         fcx.select_obligations_where_possible(fallback_has_occurred, |_| {});
326
327         // Closure and generator analysis may run after fallback
328         // because they don't constrain other type variables.
329         // Closure analysis only runs on closures. Therefore they only need to fulfill non-const predicates (as of now)
330         let prev_constness = fcx.param_env.constness();
331         fcx.param_env = fcx.param_env.without_const();
332         fcx.closure_analyze(body);
333         fcx.param_env = fcx.param_env.with_constness(prev_constness);
334         assert!(fcx.deferred_call_resolutions.borrow().is_empty());
335         // Before the generator analysis, temporary scopes shall be marked to provide more
336         // precise information on types to be captured.
337         fcx.resolve_rvalue_scopes(def_id.to_def_id());
338         fcx.resolve_generator_interiors(def_id.to_def_id());
339
340         for (ty, span, code) in fcx.deferred_sized_obligations.borrow_mut().drain(..) {
341             let ty = fcx.normalize_ty(span, ty);
342             fcx.require_type_is_sized(ty, span, code);
343         }
344
345         fcx.select_all_obligations_or_error();
346
347         if !fcx.infcx.is_tainted_by_errors() {
348             fcx.check_transmutes();
349         }
350
351         fcx.check_asms();
352
353         fcx.infcx.skip_region_resolution();
354
355         fcx.resolve_type_vars_in_body(body)
356     });
357
358     // Consistency check our TypeckResults instance can hold all ItemLocalIds
359     // it will need to hold.
360     assert_eq!(typeck_results.hir_owner, id.owner);
361
362     typeck_results
363 }
364
365 /// When `check_fn` is invoked on a generator (i.e., a body that
366 /// includes yield), it returns back some information about the yield
367 /// points.
368 struct GeneratorTypes<'tcx> {
369     /// Type of generator argument / values returned by `yield`.
370     resume_ty: Ty<'tcx>,
371
372     /// Type of value that is yielded.
373     yield_ty: Ty<'tcx>,
374
375     /// Types that are captured (see `GeneratorInterior` for more).
376     interior: Ty<'tcx>,
377
378     /// Indicates if the generator is movable or static (immovable).
379     movability: hir::Movability,
380 }
381
382 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
383 pub enum Needs {
384     MutPlace,
385     None,
386 }
387
388 impl Needs {
389     fn maybe_mut_place(m: hir::Mutability) -> Self {
390         match m {
391             hir::Mutability::Mut => Needs::MutPlace,
392             hir::Mutability::Not => Needs::None,
393         }
394     }
395 }
396
397 #[derive(Debug, Copy, Clone)]
398 pub enum PlaceOp {
399     Deref,
400     Index,
401 }
402
403 pub struct BreakableCtxt<'tcx> {
404     may_break: bool,
405
406     // this is `null` for loops where break with a value is illegal,
407     // such as `while`, `for`, and `while let`
408     coerce: Option<DynamicCoerceMany<'tcx>>,
409 }
410
411 pub struct EnclosingBreakables<'tcx> {
412     stack: Vec<BreakableCtxt<'tcx>>,
413     by_id: HirIdMap<usize>,
414 }
415
416 impl<'tcx> EnclosingBreakables<'tcx> {
417     fn find_breakable(&mut self, target_id: hir::HirId) -> &mut BreakableCtxt<'tcx> {
418         self.opt_find_breakable(target_id).unwrap_or_else(|| {
419             bug!("could not find enclosing breakable with id {}", target_id);
420         })
421     }
422
423     fn opt_find_breakable(&mut self, target_id: hir::HirId) -> Option<&mut BreakableCtxt<'tcx>> {
424         match self.by_id.get(&target_id) {
425             Some(ix) => Some(&mut self.stack[*ix]),
426             None => None,
427         }
428     }
429 }
430
431 fn report_unexpected_variant_res(tcx: TyCtxt<'_>, res: Res, qpath: &hir::QPath<'_>, span: Span) {
432     struct_span_err!(
433         tcx.sess,
434         span,
435         E0533,
436         "expected unit struct, unit variant or constant, found {} `{}`",
437         res.descr(),
438         rustc_hir_pretty::qpath_to_string(qpath),
439     )
440     .emit();
441 }
442
443 /// Controls whether the arguments are tupled. This is used for the call
444 /// operator.
445 ///
446 /// Tupling means that all call-side arguments are packed into a tuple and
447 /// passed as a single parameter. For example, if tupling is enabled, this
448 /// function:
449 /// ```
450 /// fn f(x: (isize, isize)) {}
451 /// ```
452 /// Can be called as:
453 /// ```ignore UNSOLVED (can this be done in user code?)
454 /// # fn f(x: (isize, isize)) {}
455 /// f(1, 2);
456 /// ```
457 /// Instead of:
458 /// ```
459 /// # fn f(x: (isize, isize)) {}
460 /// f((1, 2));
461 /// ```
462 #[derive(Clone, Eq, PartialEq)]
463 enum TupleArgumentsFlag {
464     DontTupleArguments,
465     TupleArguments,
466 }
467
468 fn fatally_break_rust(sess: &Session) {
469     let handler = sess.diagnostic();
470     handler.span_bug_no_panic(
471         MultiSpan::new(),
472         "It looks like you're trying to break rust; would you like some ICE?",
473     );
474     handler.note_without_error("the compiler expectedly panicked. this is a feature.");
475     handler.note_without_error(
476         "we would appreciate a joke overview: \
477          https://github.com/rust-lang/rust/issues/43162#issuecomment-320764675",
478     );
479     handler.note_without_error(&format!(
480         "rustc {} running on {}",
481         option_env!("CFG_VERSION").unwrap_or("unknown_version"),
482         config::host_triple(),
483     ));
484 }
485
486 fn has_expected_num_generic_args<'tcx>(
487     tcx: TyCtxt<'tcx>,
488     trait_did: Option<DefId>,
489     expected: usize,
490 ) -> bool {
491     trait_did.map_or(true, |trait_did| {
492         let generics = tcx.generics_of(trait_did);
493         generics.count() == expected + if generics.has_self { 1 } else { 0 }
494     })
495 }
496
497 pub fn provide(providers: &mut Providers) {
498     method::provide(providers);
499     *providers = Providers {
500         typeck_item_bodies,
501         typeck_const_arg,
502         typeck,
503         diagnostic_only_typeck,
504         has_typeck_results,
505         used_trait_imports,
506         ..*providers
507     };
508 }