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