5 Within the check phase of type check, we check each item one at a time
6 (bodies of function expressions are checked as part of the containing
7 function). Inference is used to supply types wherever they are unknown.
9 By far the most complex case is checking the body of a function. This
10 can be broken down into several distinct phases:
12 - gather: creates type variables to represent the type of each local
13 variable and pattern binding.
15 - main: the main pass does the lion's share of the work: it
16 determines the types of all expressions, resolves
17 methods, checks for most invalid conditions, and so forth. In
18 some cases, where a type is unknown, it may create a type or region
19 variable and use that as the type of an expression.
21 In the process of checking, various constraints will be placed on
22 these type variables through the subtyping relationships requested
23 through the `demand` module. The `infer` module is in charge
24 of resolving those constraints.
26 - regionck: after main is complete, the regionck pass goes over all
27 types looking for regions and making sure that they did not escape
28 into places they are not in scope. This may also influence the
29 final assignments of the various region variables if there is some
32 - writeback: writes the final types within a function body, replacing
33 type variables with their final inferred types. These final types
34 are written into the `tcx.node_types` table, which should *never* contain
35 any reference to a type variable.
39 While type checking a function, the intermediate types for the
40 expressions, blocks, and so forth contained within the function are
41 stored in `fcx.node_types` and `fcx.node_substs`. These types
42 may contain unresolved type variables. After type checking is
43 complete, the functions in the writeback module are used to take the
44 types from this table, resolve them, and then write them into their
45 permanent home in the type context `tcx`.
47 This means that during inferencing you should use `fcx.write_ty()`
48 and `fcx.expr_ty()` / `fcx.node_ty()` to write/obtain the types of
49 nodes within the function.
51 The types of top-level items, which never contain unbound type
52 variables, are stored directly into the `tcx` typeck_results.
54 N.B., a type variable is not the same thing as a type parameter. A
55 type variable is an instance of a type parameter. That is,
56 given a generic function `fn foo<T>(t: T)`, while checking the
57 function `foo`, the type `ty_param(0)` refers to the type `T`, which
58 is treated in abstract. However, when `foo()` is called, `T` will be
59 substituted for a fresh type variable `N`. This variable will
60 eventually be resolved to some concrete type (which might itself be
81 mod generator_interior;
91 pub mod rvalue_scopes;
97 check_abi, check_fn, check_impl_item_well_formed, check_item_well_formed, check_mod_item_types,
98 check_trait_item_well_formed,
100 pub use check::{check_item_type, check_wf_new};
101 pub use diverges::Diverges;
102 pub use expectation::Expectation;
104 use hir::def::CtorOf;
105 pub use inherited::{Inherited, InheritedBuilder};
107 use crate::astconv::AstConv;
108 use crate::check::gather_locals::GatherLocalsVisitor;
109 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
111 pluralize, struct_span_err, Applicability, DiagnosticBuilder, EmissionGuarantee, MultiSpan,
113 use rustc_hir as hir;
114 use rustc_hir::def::Res;
115 use rustc_hir::def_id::{DefId, LocalDefId};
116 use rustc_hir::intravisit::Visitor;
117 use rustc_hir::{HirIdMap, ImplicitSelfKind, Node};
118 use rustc_index::bit_set::BitSet;
119 use rustc_index::vec::Idx;
120 use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
121 use rustc_middle::ty::query::Providers;
122 use rustc_middle::ty::subst::{InternalSubsts, Subst, SubstsRef};
123 use rustc_middle::ty::{self, Ty, TyCtxt, UserType};
124 use rustc_session::config;
125 use rustc_session::parse::feature_err;
126 use rustc_session::Session;
127 use rustc_span::source_map::DUMMY_SP;
128 use rustc_span::symbol::{kw, Ident};
129 use rustc_span::{self, BytePos, Span};
130 use rustc_target::abi::VariantIdx;
131 use rustc_target::spec::abi::Abi;
132 use rustc_trait_selection::traits;
133 use rustc_trait_selection::traits::error_reporting::recursive_type_with_infinite_size_error;
134 use rustc_trait_selection::traits::error_reporting::suggestions::ReturnsVisitor;
136 use std::cell::{Ref, RefCell, RefMut};
138 use crate::require_c_abi_if_c_variadic;
139 use crate::util::common::indenter;
141 use self::coercion::DynamicCoerceMany;
142 use self::region::region_scope_tree;
143 pub use self::Expectation::*;
146 macro_rules! type_error_struct {
147 ($session:expr, $span:expr, $typ:expr, $code:ident, $($message:tt)*) => ({
148 let mut err = rustc_errors::struct_span_err!($session, $span, $code, $($message)*);
150 if $typ.references_error() {
151 err.downgrade_to_delayed_bug();
158 /// The type of a local binding, including the revealed type for anon types.
159 #[derive(Copy, Clone, Debug)]
160 pub struct LocalTy<'tcx> {
162 revealed_ty: Ty<'tcx>,
165 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
172 fn maybe_mut_place(m: hir::Mutability) -> Self {
174 hir::Mutability::Mut => Needs::MutPlace,
175 hir::Mutability::Not => Needs::None,
180 #[derive(Copy, Clone)]
181 pub struct UnsafetyState {
183 pub unsafety: hir::Unsafety,
188 pub fn function(unsafety: hir::Unsafety, def: hir::HirId) -> UnsafetyState {
189 UnsafetyState { def, unsafety, from_fn: true }
192 pub fn recurse(self, blk: &hir::Block<'_>) -> UnsafetyState {
193 use hir::BlockCheckMode;
194 match self.unsafety {
195 // If this unsafe, then if the outer function was already marked as
196 // unsafe we shouldn't attribute the unsafe'ness to the block. This
197 // way the block can be warned about instead of ignoring this
198 // extraneous block (functions are never warned about).
199 hir::Unsafety::Unsafe if self.from_fn => self,
202 let (unsafety, def) = match blk.rules {
203 BlockCheckMode::UnsafeBlock(..) => (hir::Unsafety::Unsafe, blk.hir_id),
204 BlockCheckMode::DefaultBlock => (unsafety, self.def),
206 UnsafetyState { def, unsafety, from_fn: false }
212 #[derive(Debug, Copy, Clone)]
218 pub struct BreakableCtxt<'tcx> {
221 // this is `null` for loops where break with a value is illegal,
222 // such as `while`, `for`, and `while let`
223 coerce: Option<DynamicCoerceMany<'tcx>>,
226 pub struct EnclosingBreakables<'tcx> {
227 stack: Vec<BreakableCtxt<'tcx>>,
228 by_id: HirIdMap<usize>,
231 impl<'tcx> EnclosingBreakables<'tcx> {
232 fn find_breakable(&mut self, target_id: hir::HirId) -> &mut BreakableCtxt<'tcx> {
233 self.opt_find_breakable(target_id).unwrap_or_else(|| {
234 bug!("could not find enclosing breakable with id {}", target_id);
238 fn opt_find_breakable(&mut self, target_id: hir::HirId) -> Option<&mut BreakableCtxt<'tcx>> {
239 match self.by_id.get(&target_id) {
240 Some(ix) => Some(&mut self.stack[*ix]),
246 pub fn provide(providers: &mut Providers) {
247 method::provide(providers);
248 *providers = Providers {
252 diagnostic_only_typeck,
256 check_item_well_formed,
257 check_trait_item_well_formed,
258 check_impl_item_well_formed,
259 check_mod_item_types,
265 fn adt_destructor(tcx: TyCtxt<'_>, def_id: DefId) -> Option<ty::Destructor> {
266 tcx.calculate_dtor(def_id, dropck::check_drop_impl)
269 /// If this `DefId` is a "primary tables entry", returns
270 /// `Some((body_id, body_ty, fn_sig))`. Otherwise, returns `None`.
272 /// If this function returns `Some`, then `typeck_results(def_id)` will
273 /// succeed; if it returns `None`, then `typeck_results(def_id)` may or
274 /// may not succeed. In some cases where this function returns `None`
275 /// (notably closures), `typeck_results(def_id)` would wind up
276 /// redirecting to the owning function.
280 ) -> Option<(hir::BodyId, Option<&hir::Ty<'_>>, Option<&hir::FnSig<'_>>)> {
281 match tcx.hir().get(id) {
282 Node::Item(item) => match item.kind {
283 hir::ItemKind::Const(ty, body) | hir::ItemKind::Static(ty, _, body) => {
284 Some((body, Some(ty), None))
286 hir::ItemKind::Fn(ref sig, .., body) => Some((body, None, Some(sig))),
289 Node::TraitItem(item) => match item.kind {
290 hir::TraitItemKind::Const(ty, Some(body)) => Some((body, Some(ty), None)),
291 hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Provided(body)) => {
292 Some((body, None, Some(sig)))
296 Node::ImplItem(item) => match item.kind {
297 hir::ImplItemKind::Const(ty, body) => Some((body, Some(ty), None)),
298 hir::ImplItemKind::Fn(ref sig, body) => Some((body, None, Some(sig))),
301 Node::AnonConst(constant) => Some((constant.body, None, None)),
306 fn has_typeck_results(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
307 // Closures' typeck results come from their outermost function,
308 // as they are part of the same "inference environment".
309 let typeck_root_def_id = tcx.typeck_root_def_id(def_id);
310 if typeck_root_def_id != def_id {
311 return tcx.has_typeck_results(typeck_root_def_id);
314 if let Some(def_id) = def_id.as_local() {
315 let id = tcx.hir().local_def_id_to_hir_id(def_id);
316 primary_body_of(tcx, id).is_some()
322 fn used_trait_imports(tcx: TyCtxt<'_>, def_id: LocalDefId) -> &FxHashSet<LocalDefId> {
323 &*tcx.typeck(def_id).used_trait_imports
326 fn typeck_const_arg<'tcx>(
328 (did, param_did): (LocalDefId, DefId),
329 ) -> &ty::TypeckResults<'tcx> {
330 let fallback = move || tcx.type_of(param_did);
331 typeck_with_fallback(tcx, did, fallback)
334 fn typeck<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &ty::TypeckResults<'tcx> {
335 if let Some(param_did) = tcx.opt_const_param_of(def_id) {
336 tcx.typeck_const_arg((def_id, param_did))
338 let fallback = move || tcx.type_of(def_id.to_def_id());
339 typeck_with_fallback(tcx, def_id, fallback)
343 /// Used only to get `TypeckResults` for type inference during error recovery.
344 /// Currently only used for type inference of `static`s and `const`s to avoid type cycle errors.
345 fn diagnostic_only_typeck<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &ty::TypeckResults<'tcx> {
346 let fallback = move || {
347 let span = tcx.hir().span(tcx.hir().local_def_id_to_hir_id(def_id));
348 tcx.ty_error_with_message(span, "diagnostic only typeck table used")
350 typeck_with_fallback(tcx, def_id, fallback)
353 #[instrument(skip(tcx, fallback))]
354 fn typeck_with_fallback<'tcx>(
357 fallback: impl Fn() -> Ty<'tcx> + 'tcx,
358 ) -> &'tcx ty::TypeckResults<'tcx> {
359 // Closures' typeck results come from their outermost function,
360 // as they are part of the same "inference environment".
361 let typeck_root_def_id = tcx.typeck_root_def_id(def_id.to_def_id()).expect_local();
362 if typeck_root_def_id != def_id {
363 return tcx.typeck(typeck_root_def_id);
366 let id = tcx.hir().local_def_id_to_hir_id(def_id);
367 let span = tcx.hir().span(id);
369 // Figure out what primary body this item has.
370 let (body_id, body_ty, fn_sig) = primary_body_of(tcx, id).unwrap_or_else(|| {
371 span_bug!(span, "can't type-check body of {:?}", def_id);
373 let body = tcx.hir().body(body_id);
375 let typeck_results = Inherited::build(tcx, def_id).enter(|inh| {
376 let param_env = tcx.param_env(def_id);
377 let (fcx, wf_tys) = if let Some(hir::FnSig { header, decl, .. }) = fn_sig {
378 let fn_sig = if crate::collect::get_infer_ret_ty(&decl.output).is_some() {
379 let fcx = FnCtxt::new(&inh, param_env, body.value.hir_id);
380 <dyn AstConv<'_>>::ty_of_fn(&fcx, id, header.unsafety, header.abi, decl, None, None)
385 check_abi(tcx, id, span, fn_sig.abi());
387 // When normalizing the function signature, we assume all types are
388 // well-formed. So, we don't need to worry about the obligations
389 // from normalization. We could just discard these, but to align with
390 // compare_method and elsewhere, we just add implied bounds for
392 let mut wf_tys = FxHashSet::default();
393 // Compute the fty from point of view of inside the fn.
394 let fn_sig = tcx.liberate_late_bound_regions(def_id.to_def_id(), fn_sig);
395 let fn_sig = inh.normalize_associated_types_in(
401 wf_tys.extend(fn_sig.inputs_and_output.iter());
403 let fcx = check_fn(&inh, param_env, fn_sig, decl, id, body, None, true).0;
406 let fcx = FnCtxt::new(&inh, param_env, body.value.hir_id);
407 let expected_type = body_ty
408 .and_then(|ty| match ty.kind {
409 hir::TyKind::Infer => Some(<dyn AstConv<'_>>::ast_ty_to_ty(&fcx, ty)),
412 .unwrap_or_else(|| match tcx.hir().get(id) {
413 Node::AnonConst(_) => match tcx.hir().get(tcx.hir().get_parent_node(id)) {
414 Node::Expr(&hir::Expr {
415 kind: hir::ExprKind::ConstBlock(ref anon_const),
417 }) if anon_const.hir_id == id => fcx.next_ty_var(TypeVariableOrigin {
418 kind: TypeVariableOriginKind::TypeInference,
422 kind: hir::TyKind::Typeof(ref anon_const), ..
423 }) if anon_const.hir_id == id => fcx.next_ty_var(TypeVariableOrigin {
424 kind: TypeVariableOriginKind::TypeInference,
427 Node::Expr(&hir::Expr { kind: hir::ExprKind::InlineAsm(asm), .. })
428 | Node::Item(&hir::Item { kind: hir::ItemKind::GlobalAsm(asm), .. }) => {
432 .filter_map(|(op, _op_sp)| match op {
433 hir::InlineAsmOperand::Const { anon_const }
434 if anon_const.hir_id == id =>
436 // Inline assembly constants must be integers.
437 Some(fcx.next_int_var())
439 hir::InlineAsmOperand::SymFn { anon_const }
440 if anon_const.hir_id == id =>
442 Some(fcx.next_ty_var(TypeVariableOrigin {
443 kind: TypeVariableOriginKind::MiscVariable,
450 operand_ty.unwrap_or_else(fallback)
457 let expected_type = fcx.normalize_associated_types_in(body.value.span, expected_type);
458 fcx.require_type_is_sized(expected_type, body.value.span, traits::ConstSized);
460 // Gather locals in statics (because of block expressions).
461 GatherLocalsVisitor::new(&fcx).visit_body(body);
463 fcx.check_expr_coercable_to_type(&body.value, expected_type, None);
465 fcx.write_ty(id, expected_type);
467 (fcx, FxHashSet::default())
470 let fallback_has_occurred = fcx.type_inference_fallback();
472 // Even though coercion casts provide type hints, we check casts after fallback for
473 // backwards compatibility. This makes fallback a stronger type hint than a cast coercion.
475 fcx.select_obligations_where_possible(fallback_has_occurred, |_| {});
477 // Closure and generator analysis may run after fallback
478 // because they don't constrain other type variables.
479 fcx.closure_analyze(body);
480 assert!(fcx.deferred_call_resolutions.borrow().is_empty());
481 // Before the generator analysis, temporary scopes shall be marked to provide more
482 // precise information on types to be captured.
483 fcx.resolve_rvalue_scopes(def_id.to_def_id());
484 fcx.resolve_generator_interiors(def_id.to_def_id());
486 for (ty, span, code) in fcx.deferred_sized_obligations.borrow_mut().drain(..) {
487 let ty = fcx.normalize_ty(span, ty);
488 fcx.require_type_is_sized(ty, span, code);
491 fcx.select_all_obligations_or_error();
493 if !fcx.infcx.is_tainted_by_errors() {
494 fcx.check_transmutes();
499 if fn_sig.is_some() {
500 fcx.regionck_fn(id, body, span, wf_tys);
502 fcx.regionck_expr(body);
505 fcx.resolve_type_vars_in_body(body)
508 // Consistency check our TypeckResults instance can hold all ItemLocalIds
509 // it will need to hold.
510 assert_eq!(typeck_results.hir_owner, id.owner);
515 /// When `check_fn` is invoked on a generator (i.e., a body that
516 /// includes yield), it returns back some information about the yield
518 struct GeneratorTypes<'tcx> {
519 /// Type of generator argument / values returned by `yield`.
522 /// Type of value that is yielded.
525 /// Types that are captured (see `GeneratorInterior` for more).
528 /// Indicates if the generator is movable or static (immovable).
529 movability: hir::Movability,
532 /// Given a `DefId` for an opaque type in return position, find its parent item's return
534 fn get_owner_return_paths<'tcx>(
537 ) -> Option<(LocalDefId, ReturnsVisitor<'tcx>)> {
538 let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
539 let parent_id = tcx.hir().get_parent_item(hir_id);
540 tcx.hir().find_by_def_id(parent_id).and_then(|node| node.body_id()).map(|body_id| {
541 let body = tcx.hir().body(body_id);
542 let mut visitor = ReturnsVisitor::default();
543 visitor.visit_body(body);
548 // Forbid defining intrinsics in Rust code,
549 // as they must always be defined by the compiler.
550 fn fn_maybe_err(tcx: TyCtxt<'_>, sp: Span, abi: Abi) {
551 if let Abi::RustIntrinsic | Abi::PlatformIntrinsic = abi {
552 tcx.sess.span_err(sp, "intrinsic must be in `extern \"rust-intrinsic\" { ... }` block");
556 fn maybe_check_static_with_link_section(tcx: TyCtxt<'_>, id: LocalDefId, span: Span) {
557 // Only restricted on wasm target for now
558 if !tcx.sess.target.is_like_wasm {
562 // If `#[link_section]` is missing, then nothing to verify
563 let attrs = tcx.codegen_fn_attrs(id);
564 if attrs.link_section.is_none() {
568 // For the wasm32 target statics with `#[link_section]` are placed into custom
569 // sections of the final output file, but this isn't link custom sections of
570 // other executable formats. Namely we can only embed a list of bytes,
571 // nothing with pointers to anything else or relocations. If any relocation
572 // show up, reject them here.
573 // `#[link_section]` may contain arbitrary, or even undefined bytes, but it is
574 // the consumer's responsibility to ensure all bytes that have been read
575 // have defined values.
576 if let Ok(alloc) = tcx.eval_static_initializer(id.to_def_id())
577 && alloc.inner().relocations().len() != 0
579 let msg = "statics with a custom `#[link_section]` must be a \
580 simple list of bytes on the wasm target with no \
581 extra levels of indirection such as references";
582 tcx.sess.span_err(span, msg);
586 fn report_forbidden_specialization(
588 impl_item: &hir::ImplItemRef,
591 let mut err = struct_span_err!(
595 "`{}` specializes an item from a parent `impl`, but \
596 that item is not marked `default`",
599 err.span_label(impl_item.span, format!("cannot specialize default item `{}`", impl_item.ident));
601 match tcx.span_of_impl(parent_impl) {
603 err.span_label(span, "parent `impl` is here");
605 "to specialize, `{}` in the parent `impl` must be marked `default`",
610 err.note(&format!("parent implementation is in crate `{cname}`"));
617 fn missing_items_err(
620 missing_items: &[&ty::AssocItem],
621 full_impl_span: Span,
623 let missing_items_msg = missing_items
625 .map(|trait_item| trait_item.name.to_string())
629 let mut err = struct_span_err!(
633 "not all trait items implemented, missing: `{missing_items_msg}`",
635 err.span_label(impl_span, format!("missing `{missing_items_msg}` in implementation"));
637 // `Span` before impl block closing brace.
638 let hi = full_impl_span.hi() - BytePos(1);
639 // Point at the place right before the closing brace of the relevant `impl` to suggest
640 // adding the associated item at the end of its body.
641 let sugg_sp = full_impl_span.with_lo(hi).with_hi(hi);
642 // Obtain the level of indentation ending in `sugg_sp`.
643 let indentation = tcx.sess.source_map().span_to_margin(sugg_sp).unwrap_or(0);
644 // Make the whitespace that will make the suggestion have the right indentation.
645 let padding: String = " ".repeat(indentation);
647 for trait_item in missing_items {
648 let snippet = suggestion_signature(trait_item, tcx);
649 let code = format!("{}{}\n{}", padding, snippet, padding);
650 let msg = format!("implement the missing item: `{snippet}`");
651 let appl = Applicability::HasPlaceholders;
652 if let Some(span) = tcx.hir().span_if_local(trait_item.def_id) {
653 err.span_label(span, format!("`{}` from trait", trait_item.name));
654 err.tool_only_span_suggestion(sugg_sp, &msg, code, appl);
656 err.span_suggestion_hidden(sugg_sp, &msg, code, appl);
662 fn missing_items_must_implement_one_of_err(
665 missing_items: &[Ident],
666 annotation_span: Option<Span>,
668 let missing_items_msg =
669 missing_items.iter().map(Ident::to_string).collect::<Vec<_>>().join("`, `");
671 let mut err = struct_span_err!(
675 "not all trait items implemented, missing one of: `{missing_items_msg}`",
677 err.span_label(impl_span, format!("missing one of `{missing_items_msg}` in implementation"));
679 if let Some(annotation_span) = annotation_span {
680 err.span_note(annotation_span, "required because of this annotation");
686 /// Re-sugar `ty::GenericPredicates` in a way suitable to be used in structured suggestions.
687 fn bounds_from_generic_predicates<'tcx>(
689 predicates: ty::GenericPredicates<'tcx>,
690 ) -> (String, String) {
691 let mut types: FxHashMap<Ty<'tcx>, Vec<DefId>> = FxHashMap::default();
692 let mut projections = vec![];
693 for (predicate, _) in predicates.predicates {
694 debug!("predicate {:?}", predicate);
695 let bound_predicate = predicate.kind();
696 match bound_predicate.skip_binder() {
697 ty::PredicateKind::Trait(trait_predicate) => {
698 let entry = types.entry(trait_predicate.self_ty()).or_default();
699 let def_id = trait_predicate.def_id();
700 if Some(def_id) != tcx.lang_items().sized_trait() {
701 // Type params are `Sized` by default, do not add that restriction to the list
702 // if it is a positive requirement.
703 entry.push(trait_predicate.def_id());
706 ty::PredicateKind::Projection(projection_pred) => {
707 projections.push(bound_predicate.rebind(projection_pred));
712 let generics = if types.is_empty() {
719 .filter_map(|t| match t.kind() {
720 ty::Param(_) => Some(t.to_string()),
721 // Avoid suggesting the following:
722 // fn foo<T, <T as Trait>::Bar>(_: T) where T: Trait, <T as Trait>::Bar: Other {}
729 let mut where_clauses = vec![];
730 for (ty, bounds) in types {
732 .extend(bounds.into_iter().map(|bound| format!("{}: {}", ty, tcx.def_path_str(bound))));
734 for projection in &projections {
735 let p = projection.skip_binder();
736 // FIXME: this is not currently supported syntax, we should be looking at the `types` and
737 // insert the associated types where they correspond, but for now let's be "lazy" and
738 // propose this instead of the following valid resugaring:
739 // `T: Trait, Trait::Assoc = K` → `T: Trait<Assoc = K>`
740 where_clauses.push(format!(
742 tcx.def_path_str(p.projection_ty.item_def_id),
746 let where_clauses = if where_clauses.is_empty() {
749 format!(" where {}", where_clauses.join(", "))
751 (generics, where_clauses)
754 /// Return placeholder code for the given function.
755 fn fn_sig_suggestion<'tcx>(
757 sig: ty::FnSig<'tcx>,
759 predicates: ty::GenericPredicates<'tcx>,
760 assoc: &ty::AssocItem,
767 Some(match ty.kind() {
768 ty::Param(_) if assoc.fn_has_self_parameter && i == 0 => "self".to_string(),
769 ty::Ref(reg, ref_ty, mutability) if i == 0 => {
770 let reg = format!("{reg} ");
771 let reg = match ®[..] {
775 if assoc.fn_has_self_parameter {
776 match ref_ty.kind() {
777 ty::Param(param) if param.name == kw::SelfUpper => {
778 format!("&{}{}self", reg, mutability.prefix_str())
781 _ => format!("self: {ty}"),
788 if assoc.fn_has_self_parameter && i == 0 {
789 format!("self: {ty}")
796 .chain(std::iter::once(if sig.c_variadic { Some("...".to_string()) } else { None }))
798 .collect::<Vec<String>>()
800 let output = sig.output();
801 let output = if !output.is_unit() { format!(" -> {output}") } else { String::new() };
803 let unsafety = sig.unsafety.prefix_str();
804 let (generics, where_clauses) = bounds_from_generic_predicates(tcx, predicates);
806 // FIXME: this is not entirely correct, as the lifetimes from borrowed params will
807 // not be present in the `fn` definition, not will we account for renamed
808 // lifetimes between the `impl` and the `trait`, but this should be good enough to
809 // fill in a significant portion of the missing code, and other subsequent
810 // suggestions can help the user fix the code.
811 format!("{unsafety}fn {ident}{generics}({args}){output}{where_clauses} {{ todo!() }}")
814 /// Return placeholder code for the given associated item.
815 /// Similar to `ty::AssocItem::suggestion`, but appropriate for use as the code snippet of a
816 /// structured suggestion.
817 fn suggestion_signature(assoc: &ty::AssocItem, tcx: TyCtxt<'_>) -> String {
819 ty::AssocKind::Fn => {
820 // We skip the binder here because the binder would deanonymize all
821 // late-bound regions, and we don't want method signatures to show up
822 // `as for<'r> fn(&'r MyType)`. Pretty-printing handles late-bound
823 // regions just fine, showing `fn(&MyType)`.
826 tcx.fn_sig(assoc.def_id).skip_binder(),
828 tcx.predicates_of(assoc.def_id),
832 ty::AssocKind::Type => format!("type {} = Type;", assoc.name),
833 ty::AssocKind::Const => {
834 let ty = tcx.type_of(assoc.def_id);
835 let val = expr::ty_kind_suggestion(ty).unwrap_or("value");
836 format!("const {}: {} = {};", assoc.name, ty, val)
841 /// Emit an error when encountering two or more variants in a transparent enum.
842 fn bad_variant_count<'tcx>(tcx: TyCtxt<'tcx>, adt: ty::AdtDef<'tcx>, sp: Span, did: DefId) {
843 let variant_spans: Vec<_> = adt
846 .map(|variant| tcx.hir().span_if_local(variant.def_id).unwrap())
848 let msg = format!("needs exactly one variant, but has {}", adt.variants().len(),);
849 let mut err = struct_span_err!(tcx.sess, sp, E0731, "transparent enum {msg}");
850 err.span_label(sp, &msg);
851 if let [start @ .., end] = &*variant_spans {
852 for variant_span in start {
853 err.span_label(*variant_span, "");
855 err.span_label(*end, &format!("too many variants in `{}`", tcx.def_path_str(did)));
860 /// Emit an error when encountering two or more non-zero-sized fields in a transparent
862 fn bad_non_zero_sized_fields<'tcx>(
864 adt: ty::AdtDef<'tcx>,
866 field_spans: impl Iterator<Item = Span>,
869 let msg = format!("needs at most one non-zero-sized field, but has {field_count}");
870 let mut err = struct_span_err!(
874 "{}transparent {} {}",
875 if adt.is_enum() { "the variant of a " } else { "" },
879 err.span_label(sp, &msg);
880 for sp in field_spans {
881 err.span_label(sp, "this field is non-zero-sized");
886 fn report_unexpected_variant_res(tcx: TyCtxt<'_>, res: Res, span: Span) {
891 "expected unit struct, unit variant or constant, found {}{}",
895 .span_to_snippet(span)
896 .map_or_else(|_| String::new(), |s| format!(" `{s}`",)),
901 /// Controls whether the arguments are tupled. This is used for the call
904 /// Tupling means that all call-side arguments are packed into a tuple and
905 /// passed as a single parameter. For example, if tupling is enabled, this
908 /// fn f(x: (isize, isize)) {}
910 /// Can be called as:
911 /// ```ignore UNSOLVED (can this be done in user code?)
912 /// # fn f(x: (isize, isize)) {}
917 /// # fn f(x: (isize, isize)) {}
920 #[derive(Clone, Eq, PartialEq)]
921 enum TupleArgumentsFlag {
926 /// A wrapper for `InferCtxt`'s `in_progress_typeck_results` field.
927 #[derive(Copy, Clone)]
928 struct MaybeInProgressTables<'a, 'tcx> {
929 maybe_typeck_results: Option<&'a RefCell<ty::TypeckResults<'tcx>>>,
932 impl<'a, 'tcx> MaybeInProgressTables<'a, 'tcx> {
933 fn borrow(self) -> Ref<'a, ty::TypeckResults<'tcx>> {
934 match self.maybe_typeck_results {
935 Some(typeck_results) => typeck_results.borrow(),
937 "MaybeInProgressTables: inh/fcx.typeck_results.borrow() with no typeck results"
942 fn borrow_mut(self) -> RefMut<'a, ty::TypeckResults<'tcx>> {
943 match self.maybe_typeck_results {
944 Some(typeck_results) => typeck_results.borrow_mut(),
946 "MaybeInProgressTables: inh/fcx.typeck_results.borrow_mut() with no typeck results"
952 fn typeck_item_bodies(tcx: TyCtxt<'_>, (): ()) {
953 tcx.hir().par_body_owners(|body_owner_def_id| tcx.ensure().typeck(body_owner_def_id));
956 fn fatally_break_rust(sess: &Session) {
957 let handler = sess.diagnostic();
958 handler.span_bug_no_panic(
960 "It looks like you're trying to break rust; would you like some ICE?",
962 handler.note_without_error("the compiler expectedly panicked. this is a feature.");
963 handler.note_without_error(
964 "we would appreciate a joke overview: \
965 https://github.com/rust-lang/rust/issues/43162#issuecomment-320764675",
967 handler.note_without_error(&format!(
968 "rustc {} running on {}",
969 option_env!("CFG_VERSION").unwrap_or("unknown_version"),
970 config::host_triple(),
974 fn potentially_plural_count(count: usize, word: &str) -> String {
975 format!("{} {}{}", count, word, pluralize!(count))
978 fn has_expected_num_generic_args<'tcx>(
980 trait_did: Option<DefId>,
983 trait_did.map_or(true, |trait_did| {
984 let generics = tcx.generics_of(trait_did);
985 generics.count() == expected + if generics.has_self { 1 } else { 0 }
989 /// Suggests calling the constructor of a tuple struct or enum variant
991 /// * `snippet` - The snippet of code that references the constructor
992 /// * `span` - The span of the snippet
993 /// * `params` - The number of parameters the constructor accepts
994 /// * `err` - A mutable diagnostic builder to add the suggestion to
995 fn suggest_call_constructor<G: EmissionGuarantee>(
999 err: &mut DiagnosticBuilder<'_, G>,
1001 // Note: tuple-structs don't have named fields, so just use placeholders
1002 let args = vec!["_"; params].join(", ");
1003 let applicable = if params > 0 {
1004 Applicability::HasPlaceholders
1006 // When n = 0, it's an empty-tuple struct/enum variant
1007 // so we trivially know how to construct it
1008 Applicability::MachineApplicable
1010 let kind = match kind {
1011 CtorOf::Struct => "a struct",
1012 CtorOf::Variant => "an enum variant",
1014 err.span_label(span, &format!("this is the constructor of {kind}"));
1015 err.multipart_suggestion(
1016 "call the constructor",
1017 vec![(span.shrink_to_lo(), "(".to_string()), (span.shrink_to_hi(), format!(")({args})"))],