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;
90 pub mod rvalue_scopes;
96 check_abi, check_fn, check_impl_item_well_formed, check_item_well_formed, check_mod_item_types,
97 check_trait_item_well_formed,
99 pub use check::{check_item_type, check_wf_new};
100 pub use diverges::Diverges;
101 pub use expectation::Expectation;
103 use hir::def::CtorOf;
104 pub use inherited::{Inherited, InheritedBuilder};
106 use crate::astconv::AstConv;
107 use crate::check::gather_locals::GatherLocalsVisitor;
108 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
110 pluralize, struct_span_err, Applicability, DiagnosticBuilder, EmissionGuarantee, MultiSpan,
112 use rustc_hir as hir;
113 use rustc_hir::def::Res;
114 use rustc_hir::def_id::{DefId, LocalDefId};
115 use rustc_hir::intravisit::Visitor;
116 use rustc_hir::{HirIdMap, ImplicitSelfKind, Node};
117 use rustc_index::bit_set::BitSet;
118 use rustc_index::vec::Idx;
119 use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
120 use rustc_middle::ty::query::Providers;
121 use rustc_middle::ty::subst::{InternalSubsts, Subst, SubstsRef};
122 use rustc_middle::ty::{self, Ty, TyCtxt, UserType};
123 use rustc_session::config;
124 use rustc_session::parse::feature_err;
125 use rustc_session::Session;
126 use rustc_span::source_map::DUMMY_SP;
127 use rustc_span::symbol::{kw, Ident};
128 use rustc_span::{self, BytePos, Span};
129 use rustc_target::abi::VariantIdx;
130 use rustc_target::spec::abi::Abi;
131 use rustc_trait_selection::traits;
132 use rustc_trait_selection::traits::error_reporting::recursive_type_with_infinite_size_error;
133 use rustc_trait_selection::traits::error_reporting::suggestions::ReturnsVisitor;
135 use std::cell::{Ref, RefCell, RefMut};
137 use crate::require_c_abi_if_c_variadic;
138 use crate::util::common::indenter;
140 use self::coercion::DynamicCoerceMany;
141 pub use self::Expectation::*;
144 macro_rules! type_error_struct {
145 ($session:expr, $span:expr, $typ:expr, $code:ident, $($message:tt)*) => ({
146 let mut err = rustc_errors::struct_span_err!($session, $span, $code, $($message)*);
148 if $typ.references_error() {
149 err.downgrade_to_delayed_bug();
156 /// The type of a local binding, including the revealed type for anon types.
157 #[derive(Copy, Clone, Debug)]
158 pub struct LocalTy<'tcx> {
160 revealed_ty: Ty<'tcx>,
163 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
170 fn maybe_mut_place(m: hir::Mutability) -> Self {
172 hir::Mutability::Mut => Needs::MutPlace,
173 hir::Mutability::Not => Needs::None,
178 #[derive(Copy, Clone)]
179 pub struct UnsafetyState {
181 pub unsafety: hir::Unsafety,
186 pub fn function(unsafety: hir::Unsafety, def: hir::HirId) -> UnsafetyState {
187 UnsafetyState { def, unsafety, from_fn: true }
190 pub fn recurse(self, blk: &hir::Block<'_>) -> UnsafetyState {
191 use hir::BlockCheckMode;
192 match self.unsafety {
193 // If this unsafe, then if the outer function was already marked as
194 // unsafe we shouldn't attribute the unsafe'ness to the block. This
195 // way the block can be warned about instead of ignoring this
196 // extraneous block (functions are never warned about).
197 hir::Unsafety::Unsafe if self.from_fn => self,
200 let (unsafety, def) = match blk.rules {
201 BlockCheckMode::UnsafeBlock(..) => (hir::Unsafety::Unsafe, blk.hir_id),
202 BlockCheckMode::DefaultBlock => (unsafety, self.def),
204 UnsafetyState { def, unsafety, from_fn: false }
210 #[derive(Debug, Copy, Clone)]
216 pub struct BreakableCtxt<'tcx> {
219 // this is `null` for loops where break with a value is illegal,
220 // such as `while`, `for`, and `while let`
221 coerce: Option<DynamicCoerceMany<'tcx>>,
224 pub struct EnclosingBreakables<'tcx> {
225 stack: Vec<BreakableCtxt<'tcx>>,
226 by_id: HirIdMap<usize>,
229 impl<'tcx> EnclosingBreakables<'tcx> {
230 fn find_breakable(&mut self, target_id: hir::HirId) -> &mut BreakableCtxt<'tcx> {
231 self.opt_find_breakable(target_id).unwrap_or_else(|| {
232 bug!("could not find enclosing breakable with id {}", target_id);
236 fn opt_find_breakable(&mut self, target_id: hir::HirId) -> Option<&mut BreakableCtxt<'tcx>> {
237 match self.by_id.get(&target_id) {
238 Some(ix) => Some(&mut self.stack[*ix]),
244 pub fn provide(providers: &mut Providers) {
245 method::provide(providers);
246 *providers = Providers {
250 diagnostic_only_typeck,
254 check_item_well_formed,
255 check_trait_item_well_formed,
256 check_impl_item_well_formed,
257 check_mod_item_types,
262 fn adt_destructor(tcx: TyCtxt<'_>, def_id: DefId) -> Option<ty::Destructor> {
263 tcx.calculate_dtor(def_id, dropck::check_drop_impl)
266 /// If this `DefId` is a "primary tables entry", returns
267 /// `Some((body_id, body_ty, fn_sig))`. Otherwise, returns `None`.
269 /// If this function returns `Some`, then `typeck_results(def_id)` will
270 /// succeed; if it returns `None`, then `typeck_results(def_id)` may or
271 /// may not succeed. In some cases where this function returns `None`
272 /// (notably closures), `typeck_results(def_id)` would wind up
273 /// redirecting to the owning function.
277 ) -> Option<(hir::BodyId, Option<&hir::Ty<'_>>, Option<&hir::FnSig<'_>>)> {
278 match tcx.hir().get(id) {
279 Node::Item(item) => match item.kind {
280 hir::ItemKind::Const(ty, body) | hir::ItemKind::Static(ty, _, body) => {
281 Some((body, Some(ty), None))
283 hir::ItemKind::Fn(ref sig, .., body) => Some((body, None, Some(sig))),
286 Node::TraitItem(item) => match item.kind {
287 hir::TraitItemKind::Const(ty, Some(body)) => Some((body, Some(ty), None)),
288 hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Provided(body)) => {
289 Some((body, None, Some(sig)))
293 Node::ImplItem(item) => match item.kind {
294 hir::ImplItemKind::Const(ty, body) => Some((body, Some(ty), None)),
295 hir::ImplItemKind::Fn(ref sig, body) => Some((body, None, Some(sig))),
298 Node::AnonConst(constant) => Some((constant.body, None, None)),
303 fn has_typeck_results(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
304 // Closures' typeck results come from their outermost function,
305 // as they are part of the same "inference environment".
306 let typeck_root_def_id = tcx.typeck_root_def_id(def_id);
307 if typeck_root_def_id != def_id {
308 return tcx.has_typeck_results(typeck_root_def_id);
311 if let Some(def_id) = def_id.as_local() {
312 let id = tcx.hir().local_def_id_to_hir_id(def_id);
313 primary_body_of(tcx, id).is_some()
319 fn used_trait_imports(tcx: TyCtxt<'_>, def_id: LocalDefId) -> &FxHashSet<LocalDefId> {
320 &*tcx.typeck(def_id).used_trait_imports
323 fn typeck_const_arg<'tcx>(
325 (did, param_did): (LocalDefId, DefId),
326 ) -> &ty::TypeckResults<'tcx> {
327 let fallback = move || tcx.type_of(param_did);
328 typeck_with_fallback(tcx, did, fallback)
331 fn typeck<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &ty::TypeckResults<'tcx> {
332 if let Some(param_did) = tcx.opt_const_param_of(def_id) {
333 tcx.typeck_const_arg((def_id, param_did))
335 let fallback = move || tcx.type_of(def_id.to_def_id());
336 typeck_with_fallback(tcx, def_id, fallback)
340 /// Used only to get `TypeckResults` for type inference during error recovery.
341 /// Currently only used for type inference of `static`s and `const`s to avoid type cycle errors.
342 fn diagnostic_only_typeck<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &ty::TypeckResults<'tcx> {
343 let fallback = move || {
344 let span = tcx.hir().span(tcx.hir().local_def_id_to_hir_id(def_id));
345 tcx.ty_error_with_message(span, "diagnostic only typeck table used")
347 typeck_with_fallback(tcx, def_id, fallback)
350 #[instrument(skip(tcx, fallback))]
351 fn typeck_with_fallback<'tcx>(
354 fallback: impl Fn() -> Ty<'tcx> + 'tcx,
355 ) -> &'tcx ty::TypeckResults<'tcx> {
356 // Closures' typeck results come from their outermost function,
357 // as they are part of the same "inference environment".
358 let typeck_root_def_id = tcx.typeck_root_def_id(def_id.to_def_id()).expect_local();
359 if typeck_root_def_id != def_id {
360 return tcx.typeck(typeck_root_def_id);
363 let id = tcx.hir().local_def_id_to_hir_id(def_id);
364 let span = tcx.hir().span(id);
366 // Figure out what primary body this item has.
367 let (body_id, body_ty, fn_sig) = primary_body_of(tcx, id).unwrap_or_else(|| {
368 span_bug!(span, "can't type-check body of {:?}", def_id);
370 let body = tcx.hir().body(body_id);
372 let typeck_results = Inherited::build(tcx, def_id).enter(|inh| {
373 let param_env = tcx.param_env(def_id);
374 let (fcx, wf_tys) = if let Some(hir::FnSig { header, decl, .. }) = fn_sig {
375 let fn_sig = if crate::collect::get_infer_ret_ty(&decl.output).is_some() {
376 let fcx = FnCtxt::new(&inh, param_env, body.value.hir_id);
377 <dyn AstConv<'_>>::ty_of_fn(&fcx, id, header.unsafety, header.abi, decl, None, None)
382 check_abi(tcx, id, span, fn_sig.abi());
384 // When normalizing the function signature, we assume all types are
385 // well-formed. So, we don't need to worry about the obligations
386 // from normalization. We could just discard these, but to align with
387 // compare_method and elsewhere, we just add implied bounds for
389 let mut wf_tys = FxHashSet::default();
390 // Compute the fty from point of view of inside the fn.
391 let fn_sig = tcx.liberate_late_bound_regions(def_id.to_def_id(), fn_sig);
392 let fn_sig = inh.normalize_associated_types_in(
398 wf_tys.extend(fn_sig.inputs_and_output.iter());
400 let fcx = check_fn(&inh, param_env, fn_sig, decl, id, body, None, true).0;
403 let fcx = FnCtxt::new(&inh, param_env, body.value.hir_id);
404 let expected_type = body_ty
405 .and_then(|ty| match ty.kind {
406 hir::TyKind::Infer => Some(<dyn AstConv<'_>>::ast_ty_to_ty(&fcx, ty)),
409 .unwrap_or_else(|| match tcx.hir().get(id) {
410 Node::AnonConst(_) => match tcx.hir().get(tcx.hir().get_parent_node(id)) {
411 Node::Expr(&hir::Expr {
412 kind: hir::ExprKind::ConstBlock(ref anon_const),
414 }) if anon_const.hir_id == id => fcx.next_ty_var(TypeVariableOrigin {
415 kind: TypeVariableOriginKind::TypeInference,
419 kind: hir::TyKind::Typeof(ref anon_const), ..
420 }) if anon_const.hir_id == id => fcx.next_ty_var(TypeVariableOrigin {
421 kind: TypeVariableOriginKind::TypeInference,
424 Node::Expr(&hir::Expr { kind: hir::ExprKind::InlineAsm(asm), .. })
425 | Node::Item(&hir::Item { kind: hir::ItemKind::GlobalAsm(asm), .. }) => {
429 .filter_map(|(op, _op_sp)| match op {
430 hir::InlineAsmOperand::Const { anon_const }
431 if anon_const.hir_id == id =>
433 // Inline assembly constants must be integers.
434 Some(fcx.next_int_var())
436 hir::InlineAsmOperand::SymFn { anon_const }
437 if anon_const.hir_id == id =>
439 Some(fcx.next_ty_var(TypeVariableOrigin {
440 kind: TypeVariableOriginKind::MiscVariable,
447 operand_ty.unwrap_or_else(fallback)
454 let expected_type = fcx.normalize_associated_types_in(body.value.span, expected_type);
455 fcx.require_type_is_sized(expected_type, body.value.span, traits::ConstSized);
457 // Gather locals in statics (because of block expressions).
458 GatherLocalsVisitor::new(&fcx).visit_body(body);
460 fcx.check_expr_coercable_to_type(&body.value, expected_type, None);
462 fcx.write_ty(id, expected_type);
464 (fcx, FxHashSet::default())
467 let fallback_has_occurred = fcx.type_inference_fallback();
469 // Even though coercion casts provide type hints, we check casts after fallback for
470 // backwards compatibility. This makes fallback a stronger type hint than a cast coercion.
472 fcx.select_obligations_where_possible(fallback_has_occurred, |_| {});
474 // Closure and generator analysis may run after fallback
475 // because they don't constrain other type variables.
476 fcx.closure_analyze(body);
477 assert!(fcx.deferred_call_resolutions.borrow().is_empty());
478 // Before the generator analysis, temporary scopes shall be marked to provide more
479 // precise information on types to be captured.
480 fcx.resolve_rvalue_scopes(def_id.to_def_id());
481 fcx.resolve_generator_interiors(def_id.to_def_id());
483 for (ty, span, code) in fcx.deferred_sized_obligations.borrow_mut().drain(..) {
484 let ty = fcx.normalize_ty(span, ty);
485 fcx.require_type_is_sized(ty, span, code);
488 fcx.select_all_obligations_or_error();
490 if fn_sig.is_some() {
491 fcx.regionck_fn(id, body, span, wf_tys);
493 fcx.regionck_expr(body);
496 fcx.resolve_type_vars_in_body(body)
499 // Consistency check our TypeckResults instance can hold all ItemLocalIds
500 // it will need to hold.
501 assert_eq!(typeck_results.hir_owner, id.owner);
506 /// When `check_fn` is invoked on a generator (i.e., a body that
507 /// includes yield), it returns back some information about the yield
509 struct GeneratorTypes<'tcx> {
510 /// Type of generator argument / values returned by `yield`.
513 /// Type of value that is yielded.
516 /// Types that are captured (see `GeneratorInterior` for more).
519 /// Indicates if the generator is movable or static (immovable).
520 movability: hir::Movability,
523 /// Given a `DefId` for an opaque type in return position, find its parent item's return
525 fn get_owner_return_paths<'tcx>(
528 ) -> Option<(LocalDefId, ReturnsVisitor<'tcx>)> {
529 let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
530 let parent_id = tcx.hir().get_parent_item(hir_id);
531 tcx.hir().find_by_def_id(parent_id).and_then(|node| node.body_id()).map(|body_id| {
532 let body = tcx.hir().body(body_id);
533 let mut visitor = ReturnsVisitor::default();
534 visitor.visit_body(body);
539 // Forbid defining intrinsics in Rust code,
540 // as they must always be defined by the compiler.
541 fn fn_maybe_err(tcx: TyCtxt<'_>, sp: Span, abi: Abi) {
542 if let Abi::RustIntrinsic | Abi::PlatformIntrinsic = abi {
543 tcx.sess.span_err(sp, "intrinsic must be in `extern \"rust-intrinsic\" { ... }` block");
547 fn maybe_check_static_with_link_section(tcx: TyCtxt<'_>, id: LocalDefId, span: Span) {
548 // Only restricted on wasm target for now
549 if !tcx.sess.target.is_like_wasm {
553 // If `#[link_section]` is missing, then nothing to verify
554 let attrs = tcx.codegen_fn_attrs(id);
555 if attrs.link_section.is_none() {
559 // For the wasm32 target statics with `#[link_section]` are placed into custom
560 // sections of the final output file, but this isn't link custom sections of
561 // other executable formats. Namely we can only embed a list of bytes,
562 // nothing with pointers to anything else or relocations. If any relocation
563 // show up, reject them here.
564 // `#[link_section]` may contain arbitrary, or even undefined bytes, but it is
565 // the consumer's responsibility to ensure all bytes that have been read
566 // have defined values.
567 if let Ok(alloc) = tcx.eval_static_initializer(id.to_def_id())
568 && alloc.inner().relocations().len() != 0
570 let msg = "statics with a custom `#[link_section]` must be a \
571 simple list of bytes on the wasm target with no \
572 extra levels of indirection such as references";
573 tcx.sess.span_err(span, msg);
577 fn report_forbidden_specialization(
579 impl_item: &hir::ImplItemRef,
582 let mut err = struct_span_err!(
586 "`{}` specializes an item from a parent `impl`, but \
587 that item is not marked `default`",
590 err.span_label(impl_item.span, format!("cannot specialize default item `{}`", impl_item.ident));
592 match tcx.span_of_impl(parent_impl) {
594 err.span_label(span, "parent `impl` is here");
596 "to specialize, `{}` in the parent `impl` must be marked `default`",
601 err.note(&format!("parent implementation is in crate `{cname}`"));
608 fn missing_items_err(
611 missing_items: &[&ty::AssocItem],
612 full_impl_span: Span,
614 let missing_items_msg = missing_items
616 .map(|trait_item| trait_item.name.to_string())
620 let mut err = struct_span_err!(
624 "not all trait items implemented, missing: `{missing_items_msg}`",
626 err.span_label(impl_span, format!("missing `{missing_items_msg}` in implementation"));
628 // `Span` before impl block closing brace.
629 let hi = full_impl_span.hi() - BytePos(1);
630 // Point at the place right before the closing brace of the relevant `impl` to suggest
631 // adding the associated item at the end of its body.
632 let sugg_sp = full_impl_span.with_lo(hi).with_hi(hi);
633 // Obtain the level of indentation ending in `sugg_sp`.
634 let indentation = tcx.sess.source_map().span_to_margin(sugg_sp).unwrap_or(0);
635 // Make the whitespace that will make the suggestion have the right indentation.
636 let padding: String = " ".repeat(indentation);
638 for trait_item in missing_items {
639 let snippet = suggestion_signature(trait_item, tcx);
640 let code = format!("{}{}\n{}", padding, snippet, padding);
641 let msg = format!("implement the missing item: `{snippet}`");
642 let appl = Applicability::HasPlaceholders;
643 if let Some(span) = tcx.hir().span_if_local(trait_item.def_id) {
644 err.span_label(span, format!("`{}` from trait", trait_item.name));
645 err.tool_only_span_suggestion(sugg_sp, &msg, code, appl);
647 err.span_suggestion_hidden(sugg_sp, &msg, code, appl);
653 fn missing_items_must_implement_one_of_err(
656 missing_items: &[Ident],
657 annotation_span: Option<Span>,
659 let missing_items_msg =
660 missing_items.iter().map(Ident::to_string).collect::<Vec<_>>().join("`, `");
662 let mut err = struct_span_err!(
666 "not all trait items implemented, missing one of: `{missing_items_msg}`",
668 err.span_label(impl_span, format!("missing one of `{missing_items_msg}` in implementation"));
670 if let Some(annotation_span) = annotation_span {
671 err.span_note(annotation_span, "required because of this annotation");
677 /// Re-sugar `ty::GenericPredicates` in a way suitable to be used in structured suggestions.
678 fn bounds_from_generic_predicates<'tcx>(
680 predicates: ty::GenericPredicates<'tcx>,
681 ) -> (String, String) {
682 let mut types: FxHashMap<Ty<'tcx>, Vec<DefId>> = FxHashMap::default();
683 let mut projections = vec![];
684 for (predicate, _) in predicates.predicates {
685 debug!("predicate {:?}", predicate);
686 let bound_predicate = predicate.kind();
687 match bound_predicate.skip_binder() {
688 ty::PredicateKind::Trait(trait_predicate) => {
689 let entry = types.entry(trait_predicate.self_ty()).or_default();
690 let def_id = trait_predicate.def_id();
691 if Some(def_id) != tcx.lang_items().sized_trait() {
692 // Type params are `Sized` by default, do not add that restriction to the list
693 // if it is a positive requirement.
694 entry.push(trait_predicate.def_id());
697 ty::PredicateKind::Projection(projection_pred) => {
698 projections.push(bound_predicate.rebind(projection_pred));
703 let generics = if types.is_empty() {
710 .filter_map(|t| match t.kind() {
711 ty::Param(_) => Some(t.to_string()),
712 // Avoid suggesting the following:
713 // fn foo<T, <T as Trait>::Bar>(_: T) where T: Trait, <T as Trait>::Bar: Other {}
720 let mut where_clauses = vec![];
721 for (ty, bounds) in types {
723 .extend(bounds.into_iter().map(|bound| format!("{}: {}", ty, tcx.def_path_str(bound))));
725 for projection in &projections {
726 let p = projection.skip_binder();
727 // FIXME: this is not currently supported syntax, we should be looking at the `types` and
728 // insert the associated types where they correspond, but for now let's be "lazy" and
729 // propose this instead of the following valid resugaring:
730 // `T: Trait, Trait::Assoc = K` → `T: Trait<Assoc = K>`
731 where_clauses.push(format!(
733 tcx.def_path_str(p.projection_ty.item_def_id),
737 let where_clauses = if where_clauses.is_empty() {
740 format!(" where {}", where_clauses.join(", "))
742 (generics, where_clauses)
745 /// Return placeholder code for the given function.
746 fn fn_sig_suggestion<'tcx>(
748 sig: ty::FnSig<'tcx>,
750 predicates: ty::GenericPredicates<'tcx>,
751 assoc: &ty::AssocItem,
758 Some(match ty.kind() {
759 ty::Param(_) if assoc.fn_has_self_parameter && i == 0 => "self".to_string(),
760 ty::Ref(reg, ref_ty, mutability) if i == 0 => {
761 let reg = format!("{reg} ");
762 let reg = match ®[..] {
766 if assoc.fn_has_self_parameter {
767 match ref_ty.kind() {
768 ty::Param(param) if param.name == kw::SelfUpper => {
769 format!("&{}{}self", reg, mutability.prefix_str())
772 _ => format!("self: {ty}"),
779 if assoc.fn_has_self_parameter && i == 0 {
780 format!("self: {ty}")
787 .chain(std::iter::once(if sig.c_variadic { Some("...".to_string()) } else { None }))
789 .collect::<Vec<String>>()
791 let output = sig.output();
792 let output = if !output.is_unit() { format!(" -> {output}") } else { String::new() };
794 let unsafety = sig.unsafety.prefix_str();
795 let (generics, where_clauses) = bounds_from_generic_predicates(tcx, predicates);
797 // FIXME: this is not entirely correct, as the lifetimes from borrowed params will
798 // not be present in the `fn` definition, not will we account for renamed
799 // lifetimes between the `impl` and the `trait`, but this should be good enough to
800 // fill in a significant portion of the missing code, and other subsequent
801 // suggestions can help the user fix the code.
802 format!("{unsafety}fn {ident}{generics}({args}){output}{where_clauses} {{ todo!() }}")
805 /// Return placeholder code for the given associated item.
806 /// Similar to `ty::AssocItem::suggestion`, but appropriate for use as the code snippet of a
807 /// structured suggestion.
808 fn suggestion_signature(assoc: &ty::AssocItem, tcx: TyCtxt<'_>) -> String {
810 ty::AssocKind::Fn => {
811 // We skip the binder here because the binder would deanonymize all
812 // late-bound regions, and we don't want method signatures to show up
813 // `as for<'r> fn(&'r MyType)`. Pretty-printing handles late-bound
814 // regions just fine, showing `fn(&MyType)`.
817 tcx.fn_sig(assoc.def_id).skip_binder(),
819 tcx.predicates_of(assoc.def_id),
823 ty::AssocKind::Type => format!("type {} = Type;", assoc.name),
824 ty::AssocKind::Const => {
825 let ty = tcx.type_of(assoc.def_id);
826 let val = expr::ty_kind_suggestion(ty).unwrap_or("value");
827 format!("const {}: {} = {};", assoc.name, ty, val)
832 /// Emit an error when encountering two or more variants in a transparent enum.
833 fn bad_variant_count<'tcx>(tcx: TyCtxt<'tcx>, adt: ty::AdtDef<'tcx>, sp: Span, did: DefId) {
834 let variant_spans: Vec<_> = adt
837 .map(|variant| tcx.hir().span_if_local(variant.def_id).unwrap())
839 let msg = format!("needs exactly one variant, but has {}", adt.variants().len(),);
840 let mut err = struct_span_err!(tcx.sess, sp, E0731, "transparent enum {msg}");
841 err.span_label(sp, &msg);
842 if let [start @ .., end] = &*variant_spans {
843 for variant_span in start {
844 err.span_label(*variant_span, "");
846 err.span_label(*end, &format!("too many variants in `{}`", tcx.def_path_str(did)));
851 /// Emit an error when encountering two or more non-zero-sized fields in a transparent
853 fn bad_non_zero_sized_fields<'tcx>(
855 adt: ty::AdtDef<'tcx>,
857 field_spans: impl Iterator<Item = Span>,
860 let msg = format!("needs at most one non-zero-sized field, but has {field_count}");
861 let mut err = struct_span_err!(
865 "{}transparent {} {}",
866 if adt.is_enum() { "the variant of a " } else { "" },
870 err.span_label(sp, &msg);
871 for sp in field_spans {
872 err.span_label(sp, "this field is non-zero-sized");
877 fn report_unexpected_variant_res(tcx: TyCtxt<'_>, res: Res, span: Span) {
882 "expected unit struct, unit variant or constant, found {}{}",
886 .span_to_snippet(span)
887 .map_or_else(|_| String::new(), |s| format!(" `{s}`",)),
892 /// Controls whether the arguments are tupled. This is used for the call
895 /// Tupling means that all call-side arguments are packed into a tuple and
896 /// passed as a single parameter. For example, if tupling is enabled, this
899 /// fn f(x: (isize, isize)) {}
901 /// Can be called as:
902 /// ```ignore UNSOLVED (can this be done in user code?)
903 /// # fn f(x: (isize, isize)) {}
908 /// # fn f(x: (isize, isize)) {}
911 #[derive(Clone, Eq, PartialEq)]
912 enum TupleArgumentsFlag {
917 /// A wrapper for `InferCtxt`'s `in_progress_typeck_results` field.
918 #[derive(Copy, Clone)]
919 struct MaybeInProgressTables<'a, 'tcx> {
920 maybe_typeck_results: Option<&'a RefCell<ty::TypeckResults<'tcx>>>,
923 impl<'a, 'tcx> MaybeInProgressTables<'a, 'tcx> {
924 fn borrow(self) -> Ref<'a, ty::TypeckResults<'tcx>> {
925 match self.maybe_typeck_results {
926 Some(typeck_results) => typeck_results.borrow(),
928 "MaybeInProgressTables: inh/fcx.typeck_results.borrow() with no typeck results"
933 fn borrow_mut(self) -> RefMut<'a, ty::TypeckResults<'tcx>> {
934 match self.maybe_typeck_results {
935 Some(typeck_results) => typeck_results.borrow_mut(),
937 "MaybeInProgressTables: inh/fcx.typeck_results.borrow_mut() with no typeck results"
943 fn typeck_item_bodies(tcx: TyCtxt<'_>, (): ()) {
944 tcx.hir().par_body_owners(|body_owner_def_id| tcx.ensure().typeck(body_owner_def_id));
947 fn fatally_break_rust(sess: &Session) {
948 let handler = sess.diagnostic();
949 handler.span_bug_no_panic(
951 "It looks like you're trying to break rust; would you like some ICE?",
953 handler.note_without_error("the compiler expectedly panicked. this is a feature.");
954 handler.note_without_error(
955 "we would appreciate a joke overview: \
956 https://github.com/rust-lang/rust/issues/43162#issuecomment-320764675",
958 handler.note_without_error(&format!(
959 "rustc {} running on {}",
960 option_env!("CFG_VERSION").unwrap_or("unknown_version"),
961 config::host_triple(),
965 fn potentially_plural_count(count: usize, word: &str) -> String {
966 format!("{} {}{}", count, word, pluralize!(count))
969 fn has_expected_num_generic_args<'tcx>(
971 trait_did: Option<DefId>,
974 trait_did.map_or(true, |trait_did| {
975 let generics = tcx.generics_of(trait_did);
976 generics.count() == expected + if generics.has_self { 1 } else { 0 }
980 /// Suggests calling the constructor of a tuple struct or enum variant
982 /// * `snippet` - The snippet of code that references the constructor
983 /// * `span` - The span of the snippet
984 /// * `params` - The number of parameters the constructor accepts
985 /// * `err` - A mutable diagnostic builder to add the suggestion to
986 fn suggest_call_constructor<G: EmissionGuarantee>(
990 err: &mut DiagnosticBuilder<'_, G>,
992 // Note: tuple-structs don't have named fields, so just use placeholders
993 let args = vec!["_"; params].join(", ");
994 let applicable = if params > 0 {
995 Applicability::HasPlaceholders
997 // When n = 0, it's an empty-tuple struct/enum variant
998 // so we trivially know how to construct it
999 Applicability::MachineApplicable
1001 let kind = match kind {
1002 CtorOf::Struct => "a struct",
1003 CtorOf::Variant => "an enum variant",
1005 err.span_label(span, &format!("this is the constructor of {kind}"));
1006 err.multipart_suggestion(
1007 "call the constructor",
1008 vec![(span.shrink_to_lo(), "(".to_string()), (span.shrink_to_hi(), format!(")({args})"))],