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;
96 use check::{check_abi, check_fn, check_mod_item_types};
97 pub use diverges::Diverges;
98 pub use expectation::Expectation;
100 use hir::def::CtorOf;
101 pub use inherited::{Inherited, InheritedBuilder};
103 use crate::astconv::AstConv;
104 use crate::check::gather_locals::GatherLocalsVisitor;
105 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
107 pluralize, struct_span_err, Applicability, DiagnosticBuilder, EmissionGuarantee, MultiSpan,
109 use rustc_hir as hir;
110 use rustc_hir::def::Res;
111 use rustc_hir::def_id::{DefId, LocalDefId};
112 use rustc_hir::intravisit::Visitor;
113 use rustc_hir::{HirIdMap, ImplicitSelfKind, Node};
114 use rustc_index::bit_set::BitSet;
115 use rustc_index::vec::Idx;
116 use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
117 use rustc_middle::ty::query::Providers;
118 use rustc_middle::ty::subst::{InternalSubsts, Subst, SubstsRef};
119 use rustc_middle::ty::{self, Ty, TyCtxt, UserType};
120 use rustc_session::config;
121 use rustc_session::parse::feature_err;
122 use rustc_session::Session;
123 use rustc_span::source_map::DUMMY_SP;
124 use rustc_span::symbol::{kw, Ident};
125 use rustc_span::{self, BytePos, Span};
126 use rustc_target::abi::VariantIdx;
127 use rustc_target::spec::abi::Abi;
128 use rustc_trait_selection::traits;
129 use rustc_trait_selection::traits::error_reporting::recursive_type_with_infinite_size_error;
130 use rustc_trait_selection::traits::error_reporting::suggestions::ReturnsVisitor;
132 use std::cell::{Ref, RefCell, RefMut};
134 use crate::require_c_abi_if_c_variadic;
135 use crate::util::common::indenter;
137 use self::coercion::DynamicCoerceMany;
138 use self::region::region_scope_tree;
139 pub use self::Expectation::*;
142 macro_rules! type_error_struct {
143 ($session:expr, $span:expr, $typ:expr, $code:ident, $($message:tt)*) => ({
144 let mut err = rustc_errors::struct_span_err!($session, $span, $code, $($message)*);
146 if $typ.references_error() {
147 err.downgrade_to_delayed_bug();
154 /// The type of a local binding, including the revealed type for anon types.
155 #[derive(Copy, Clone, Debug)]
156 pub struct LocalTy<'tcx> {
158 revealed_ty: Ty<'tcx>,
161 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
168 fn maybe_mut_place(m: hir::Mutability) -> Self {
170 hir::Mutability::Mut => Needs::MutPlace,
171 hir::Mutability::Not => Needs::None,
176 #[derive(Copy, Clone)]
177 pub struct UnsafetyState {
179 pub unsafety: hir::Unsafety,
184 pub fn function(unsafety: hir::Unsafety, def: hir::HirId) -> UnsafetyState {
185 UnsafetyState { def, unsafety, from_fn: true }
188 pub fn recurse(self, blk: &hir::Block<'_>) -> UnsafetyState {
189 use hir::BlockCheckMode;
190 match self.unsafety {
191 // If this unsafe, then if the outer function was already marked as
192 // unsafe we shouldn't attribute the unsafe'ness to the block. This
193 // way the block can be warned about instead of ignoring this
194 // extraneous block (functions are never warned about).
195 hir::Unsafety::Unsafe if self.from_fn => self,
198 let (unsafety, def) = match blk.rules {
199 BlockCheckMode::UnsafeBlock(..) => (hir::Unsafety::Unsafe, blk.hir_id),
200 BlockCheckMode::DefaultBlock => (unsafety, self.def),
202 UnsafetyState { def, unsafety, from_fn: false }
208 #[derive(Debug, Copy, Clone)]
214 pub struct BreakableCtxt<'tcx> {
217 // this is `null` for loops where break with a value is illegal,
218 // such as `while`, `for`, and `while let`
219 coerce: Option<DynamicCoerceMany<'tcx>>,
222 pub struct EnclosingBreakables<'tcx> {
223 stack: Vec<BreakableCtxt<'tcx>>,
224 by_id: HirIdMap<usize>,
227 impl<'tcx> EnclosingBreakables<'tcx> {
228 fn find_breakable(&mut self, target_id: hir::HirId) -> &mut BreakableCtxt<'tcx> {
229 self.opt_find_breakable(target_id).unwrap_or_else(|| {
230 bug!("could not find enclosing breakable with id {}", target_id);
234 fn opt_find_breakable(&mut self, target_id: hir::HirId) -> Option<&mut BreakableCtxt<'tcx>> {
235 match self.by_id.get(&target_id) {
236 Some(ix) => Some(&mut self.stack[*ix]),
242 pub fn provide(providers: &mut Providers) {
243 method::provide(providers);
244 wfcheck::provide(providers);
245 *providers = Providers {
249 diagnostic_only_typeck,
253 check_mod_item_types,
259 fn adt_destructor(tcx: TyCtxt<'_>, def_id: DefId) -> Option<ty::Destructor> {
260 tcx.calculate_dtor(def_id, dropck::check_drop_impl)
263 /// If this `DefId` is a "primary tables entry", returns
264 /// `Some((body_id, body_ty, fn_sig))`. Otherwise, returns `None`.
266 /// If this function returns `Some`, then `typeck_results(def_id)` will
267 /// succeed; if it returns `None`, then `typeck_results(def_id)` may or
268 /// may not succeed. In some cases where this function returns `None`
269 /// (notably closures), `typeck_results(def_id)` would wind up
270 /// redirecting to the owning function.
274 ) -> Option<(hir::BodyId, Option<&hir::Ty<'_>>, Option<&hir::FnSig<'_>>)> {
275 match tcx.hir().get(id) {
276 Node::Item(item) => match item.kind {
277 hir::ItemKind::Const(ty, body) | hir::ItemKind::Static(ty, _, body) => {
278 Some((body, Some(ty), None))
280 hir::ItemKind::Fn(ref sig, .., body) => Some((body, None, Some(sig))),
283 Node::TraitItem(item) => match item.kind {
284 hir::TraitItemKind::Const(ty, Some(body)) => Some((body, Some(ty), None)),
285 hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Provided(body)) => {
286 Some((body, None, Some(sig)))
290 Node::ImplItem(item) => match item.kind {
291 hir::ImplItemKind::Const(ty, body) => Some((body, Some(ty), None)),
292 hir::ImplItemKind::Fn(ref sig, body) => Some((body, None, Some(sig))),
295 Node::AnonConst(constant) => Some((constant.body, None, None)),
300 fn has_typeck_results(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
301 // Closures' typeck results come from their outermost function,
302 // as they are part of the same "inference environment".
303 let typeck_root_def_id = tcx.typeck_root_def_id(def_id);
304 if typeck_root_def_id != def_id {
305 return tcx.has_typeck_results(typeck_root_def_id);
308 if let Some(def_id) = def_id.as_local() {
309 let id = tcx.hir().local_def_id_to_hir_id(def_id);
310 primary_body_of(tcx, id).is_some()
316 fn used_trait_imports(tcx: TyCtxt<'_>, def_id: LocalDefId) -> &FxHashSet<LocalDefId> {
317 &*tcx.typeck(def_id).used_trait_imports
320 fn typeck_const_arg<'tcx>(
322 (did, param_did): (LocalDefId, DefId),
323 ) -> &ty::TypeckResults<'tcx> {
324 let fallback = move || tcx.type_of(param_did);
325 typeck_with_fallback(tcx, did, fallback)
328 fn typeck<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &ty::TypeckResults<'tcx> {
329 if let Some(param_did) = tcx.opt_const_param_of(def_id) {
330 tcx.typeck_const_arg((def_id, param_did))
332 let fallback = move || tcx.type_of(def_id.to_def_id());
333 typeck_with_fallback(tcx, def_id, fallback)
337 /// Used only to get `TypeckResults` for type inference during error recovery.
338 /// Currently only used for type inference of `static`s and `const`s to avoid type cycle errors.
339 fn diagnostic_only_typeck<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &ty::TypeckResults<'tcx> {
340 let fallback = move || {
341 let span = tcx.hir().span(tcx.hir().local_def_id_to_hir_id(def_id));
342 tcx.ty_error_with_message(span, "diagnostic only typeck table used")
344 typeck_with_fallback(tcx, def_id, fallback)
347 #[instrument(skip(tcx, fallback))]
348 fn typeck_with_fallback<'tcx>(
351 fallback: impl Fn() -> Ty<'tcx> + 'tcx,
352 ) -> &'tcx ty::TypeckResults<'tcx> {
353 // Closures' typeck results come from their outermost function,
354 // as they are part of the same "inference environment".
355 let typeck_root_def_id = tcx.typeck_root_def_id(def_id.to_def_id()).expect_local();
356 if typeck_root_def_id != def_id {
357 return tcx.typeck(typeck_root_def_id);
360 let id = tcx.hir().local_def_id_to_hir_id(def_id);
361 let span = tcx.hir().span(id);
363 // Figure out what primary body this item has.
364 let (body_id, body_ty, fn_sig) = primary_body_of(tcx, id).unwrap_or_else(|| {
365 span_bug!(span, "can't type-check body of {:?}", def_id);
367 let body = tcx.hir().body(body_id);
369 let typeck_results = Inherited::build(tcx, def_id).enter(|inh| {
370 let param_env = tcx.param_env(def_id);
371 let (fcx, wf_tys) = if let Some(hir::FnSig { header, decl, .. }) = fn_sig {
372 let fn_sig = if crate::collect::get_infer_ret_ty(&decl.output).is_some() {
373 let fcx = FnCtxt::new(&inh, param_env, body.value.hir_id);
374 <dyn AstConv<'_>>::ty_of_fn(&fcx, id, header.unsafety, header.abi, decl, None, None)
379 check_abi(tcx, id, span, fn_sig.abi());
381 // When normalizing the function signature, we assume all types are
382 // well-formed. So, we don't need to worry about the obligations
383 // from normalization. We could just discard these, but to align with
384 // compare_method and elsewhere, we just add implied bounds for
386 let mut wf_tys = FxHashSet::default();
387 // Compute the fty from point of view of inside the fn.
388 let fn_sig = tcx.liberate_late_bound_regions(def_id.to_def_id(), fn_sig);
389 let fn_sig = inh.normalize_associated_types_in(
395 wf_tys.extend(fn_sig.inputs_and_output.iter());
397 let fcx = check_fn(&inh, param_env, fn_sig, decl, id, body, None, true).0;
400 let fcx = FnCtxt::new(&inh, param_env, body.value.hir_id);
401 let expected_type = body_ty
402 .and_then(|ty| match ty.kind {
403 hir::TyKind::Infer => Some(<dyn AstConv<'_>>::ast_ty_to_ty(&fcx, ty)),
406 .unwrap_or_else(|| match tcx.hir().get(id) {
407 Node::AnonConst(_) => match tcx.hir().get(tcx.hir().get_parent_node(id)) {
408 Node::Expr(&hir::Expr {
409 kind: hir::ExprKind::ConstBlock(ref anon_const),
411 }) if anon_const.hir_id == id => fcx.next_ty_var(TypeVariableOrigin {
412 kind: TypeVariableOriginKind::TypeInference,
416 kind: hir::TyKind::Typeof(ref anon_const), ..
417 }) if anon_const.hir_id == id => fcx.next_ty_var(TypeVariableOrigin {
418 kind: TypeVariableOriginKind::TypeInference,
421 Node::Expr(&hir::Expr { kind: hir::ExprKind::InlineAsm(asm), .. })
422 | Node::Item(&hir::Item { kind: hir::ItemKind::GlobalAsm(asm), .. }) => {
426 .filter_map(|(op, _op_sp)| match op {
427 hir::InlineAsmOperand::Const { anon_const }
428 if anon_const.hir_id == id =>
430 // Inline assembly constants must be integers.
431 Some(fcx.next_int_var())
433 hir::InlineAsmOperand::SymFn { anon_const }
434 if anon_const.hir_id == id =>
436 Some(fcx.next_ty_var(TypeVariableOrigin {
437 kind: TypeVariableOriginKind::MiscVariable,
444 operand_ty.unwrap_or_else(fallback)
451 let expected_type = fcx.normalize_associated_types_in(body.value.span, expected_type);
452 fcx.require_type_is_sized(expected_type, body.value.span, traits::ConstSized);
454 // Gather locals in statics (because of block expressions).
455 GatherLocalsVisitor::new(&fcx).visit_body(body);
457 fcx.check_expr_coercable_to_type(&body.value, expected_type, None);
459 fcx.write_ty(id, expected_type);
461 (fcx, FxHashSet::default())
464 let fallback_has_occurred = fcx.type_inference_fallback();
466 // Even though coercion casts provide type hints, we check casts after fallback for
467 // backwards compatibility. This makes fallback a stronger type hint than a cast coercion.
469 fcx.select_obligations_where_possible(fallback_has_occurred, |_| {});
471 // Closure and generator analysis may run after fallback
472 // because they don't constrain other type variables.
473 fcx.closure_analyze(body);
474 assert!(fcx.deferred_call_resolutions.borrow().is_empty());
475 // Before the generator analysis, temporary scopes shall be marked to provide more
476 // precise information on types to be captured.
477 fcx.resolve_rvalue_scopes(def_id.to_def_id());
478 fcx.resolve_generator_interiors(def_id.to_def_id());
480 for (ty, span, code) in fcx.deferred_sized_obligations.borrow_mut().drain(..) {
481 let ty = fcx.normalize_ty(span, ty);
482 fcx.require_type_is_sized(ty, span, code);
485 fcx.select_all_obligations_or_error();
487 if !fcx.infcx.is_tainted_by_errors() {
488 fcx.check_transmutes();
493 if fn_sig.is_some() {
494 fcx.regionck_fn(id, body, span, wf_tys);
496 fcx.regionck_expr(body);
499 fcx.resolve_type_vars_in_body(body)
502 // Consistency check our TypeckResults instance can hold all ItemLocalIds
503 // it will need to hold.
504 assert_eq!(typeck_results.hir_owner, id.owner);
509 /// When `check_fn` is invoked on a generator (i.e., a body that
510 /// includes yield), it returns back some information about the yield
512 struct GeneratorTypes<'tcx> {
513 /// Type of generator argument / values returned by `yield`.
516 /// Type of value that is yielded.
519 /// Types that are captured (see `GeneratorInterior` for more).
522 /// Indicates if the generator is movable or static (immovable).
523 movability: hir::Movability,
526 /// Given a `DefId` for an opaque type in return position, find its parent item's return
528 fn get_owner_return_paths<'tcx>(
531 ) -> Option<(LocalDefId, ReturnsVisitor<'tcx>)> {
532 let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
533 let parent_id = tcx.hir().get_parent_item(hir_id);
534 tcx.hir().find_by_def_id(parent_id).and_then(|node| node.body_id()).map(|body_id| {
535 let body = tcx.hir().body(body_id);
536 let mut visitor = ReturnsVisitor::default();
537 visitor.visit_body(body);
542 // Forbid defining intrinsics in Rust code,
543 // as they must always be defined by the compiler.
544 fn fn_maybe_err(tcx: TyCtxt<'_>, sp: Span, abi: Abi) {
545 if let Abi::RustIntrinsic | Abi::PlatformIntrinsic = abi {
546 tcx.sess.span_err(sp, "intrinsic must be in `extern \"rust-intrinsic\" { ... }` block");
550 fn maybe_check_static_with_link_section(tcx: TyCtxt<'_>, id: LocalDefId, span: Span) {
551 // Only restricted on wasm target for now
552 if !tcx.sess.target.is_like_wasm {
556 // If `#[link_section]` is missing, then nothing to verify
557 let attrs = tcx.codegen_fn_attrs(id);
558 if attrs.link_section.is_none() {
562 // For the wasm32 target statics with `#[link_section]` are placed into custom
563 // sections of the final output file, but this isn't link custom sections of
564 // other executable formats. Namely we can only embed a list of bytes,
565 // nothing with pointers to anything else or relocations. If any relocation
566 // show up, reject them here.
567 // `#[link_section]` may contain arbitrary, or even undefined bytes, but it is
568 // the consumer's responsibility to ensure all bytes that have been read
569 // have defined values.
570 if let Ok(alloc) = tcx.eval_static_initializer(id.to_def_id())
571 && alloc.inner().relocations().len() != 0
573 let msg = "statics with a custom `#[link_section]` must be a \
574 simple list of bytes on the wasm target with no \
575 extra levels of indirection such as references";
576 tcx.sess.span_err(span, msg);
580 fn report_forbidden_specialization(
582 impl_item: &hir::ImplItemRef,
585 let mut err = struct_span_err!(
589 "`{}` specializes an item from a parent `impl`, but \
590 that item is not marked `default`",
593 err.span_label(impl_item.span, format!("cannot specialize default item `{}`", impl_item.ident));
595 match tcx.span_of_impl(parent_impl) {
597 err.span_label(span, "parent `impl` is here");
599 "to specialize, `{}` in the parent `impl` must be marked `default`",
604 err.note(&format!("parent implementation is in crate `{cname}`"));
611 fn missing_items_err(
614 missing_items: &[&ty::AssocItem],
615 full_impl_span: Span,
617 let missing_items_msg = missing_items
619 .map(|trait_item| trait_item.name.to_string())
623 let mut err = struct_span_err!(
627 "not all trait items implemented, missing: `{missing_items_msg}`",
629 err.span_label(impl_span, format!("missing `{missing_items_msg}` in implementation"));
631 // `Span` before impl block closing brace.
632 let hi = full_impl_span.hi() - BytePos(1);
633 // Point at the place right before the closing brace of the relevant `impl` to suggest
634 // adding the associated item at the end of its body.
635 let sugg_sp = full_impl_span.with_lo(hi).with_hi(hi);
636 // Obtain the level of indentation ending in `sugg_sp`.
637 let indentation = tcx.sess.source_map().span_to_margin(sugg_sp).unwrap_or(0);
638 // Make the whitespace that will make the suggestion have the right indentation.
639 let padding: String = " ".repeat(indentation);
641 for trait_item in missing_items {
642 let snippet = suggestion_signature(trait_item, tcx);
643 let code = format!("{}{}\n{}", padding, snippet, padding);
644 let msg = format!("implement the missing item: `{snippet}`");
645 let appl = Applicability::HasPlaceholders;
646 if let Some(span) = tcx.hir().span_if_local(trait_item.def_id) {
647 err.span_label(span, format!("`{}` from trait", trait_item.name));
648 err.tool_only_span_suggestion(sugg_sp, &msg, code, appl);
650 err.span_suggestion_hidden(sugg_sp, &msg, code, appl);
656 fn missing_items_must_implement_one_of_err(
659 missing_items: &[Ident],
660 annotation_span: Option<Span>,
662 let missing_items_msg =
663 missing_items.iter().map(Ident::to_string).collect::<Vec<_>>().join("`, `");
665 let mut err = struct_span_err!(
669 "not all trait items implemented, missing one of: `{missing_items_msg}`",
671 err.span_label(impl_span, format!("missing one of `{missing_items_msg}` in implementation"));
673 if let Some(annotation_span) = annotation_span {
674 err.span_note(annotation_span, "required because of this annotation");
680 /// Re-sugar `ty::GenericPredicates` in a way suitable to be used in structured suggestions.
681 fn bounds_from_generic_predicates<'tcx>(
683 predicates: ty::GenericPredicates<'tcx>,
684 ) -> (String, String) {
685 let mut types: FxHashMap<Ty<'tcx>, Vec<DefId>> = FxHashMap::default();
686 let mut projections = vec![];
687 for (predicate, _) in predicates.predicates {
688 debug!("predicate {:?}", predicate);
689 let bound_predicate = predicate.kind();
690 match bound_predicate.skip_binder() {
691 ty::PredicateKind::Trait(trait_predicate) => {
692 let entry = types.entry(trait_predicate.self_ty()).or_default();
693 let def_id = trait_predicate.def_id();
694 if Some(def_id) != tcx.lang_items().sized_trait() {
695 // Type params are `Sized` by default, do not add that restriction to the list
696 // if it is a positive requirement.
697 entry.push(trait_predicate.def_id());
700 ty::PredicateKind::Projection(projection_pred) => {
701 projections.push(bound_predicate.rebind(projection_pred));
706 let generics = if types.is_empty() {
713 .filter_map(|t| match t.kind() {
714 ty::Param(_) => Some(t.to_string()),
715 // Avoid suggesting the following:
716 // fn foo<T, <T as Trait>::Bar>(_: T) where T: Trait, <T as Trait>::Bar: Other {}
723 let mut where_clauses = vec![];
724 for (ty, bounds) in types {
726 .extend(bounds.into_iter().map(|bound| format!("{}: {}", ty, tcx.def_path_str(bound))));
728 for projection in &projections {
729 let p = projection.skip_binder();
730 // FIXME: this is not currently supported syntax, we should be looking at the `types` and
731 // insert the associated types where they correspond, but for now let's be "lazy" and
732 // propose this instead of the following valid resugaring:
733 // `T: Trait, Trait::Assoc = K` → `T: Trait<Assoc = K>`
734 where_clauses.push(format!(
736 tcx.def_path_str(p.projection_ty.item_def_id),
740 let where_clauses = if where_clauses.is_empty() {
743 format!(" where {}", where_clauses.join(", "))
745 (generics, where_clauses)
748 /// Return placeholder code for the given function.
749 fn fn_sig_suggestion<'tcx>(
751 sig: ty::FnSig<'tcx>,
753 predicates: ty::GenericPredicates<'tcx>,
754 assoc: &ty::AssocItem,
761 Some(match ty.kind() {
762 ty::Param(_) if assoc.fn_has_self_parameter && i == 0 => "self".to_string(),
763 ty::Ref(reg, ref_ty, mutability) if i == 0 => {
764 let reg = format!("{reg} ");
765 let reg = match ®[..] {
769 if assoc.fn_has_self_parameter {
770 match ref_ty.kind() {
771 ty::Param(param) if param.name == kw::SelfUpper => {
772 format!("&{}{}self", reg, mutability.prefix_str())
775 _ => format!("self: {ty}"),
782 if assoc.fn_has_self_parameter && i == 0 {
783 format!("self: {ty}")
790 .chain(std::iter::once(if sig.c_variadic { Some("...".to_string()) } else { None }))
792 .collect::<Vec<String>>()
794 let output = sig.output();
795 let output = if !output.is_unit() { format!(" -> {output}") } else { String::new() };
797 let unsafety = sig.unsafety.prefix_str();
798 let (generics, where_clauses) = bounds_from_generic_predicates(tcx, predicates);
800 // FIXME: this is not entirely correct, as the lifetimes from borrowed params will
801 // not be present in the `fn` definition, not will we account for renamed
802 // lifetimes between the `impl` and the `trait`, but this should be good enough to
803 // fill in a significant portion of the missing code, and other subsequent
804 // suggestions can help the user fix the code.
805 format!("{unsafety}fn {ident}{generics}({args}){output}{where_clauses} {{ todo!() }}")
808 /// Return placeholder code for the given associated item.
809 /// Similar to `ty::AssocItem::suggestion`, but appropriate for use as the code snippet of a
810 /// structured suggestion.
811 fn suggestion_signature(assoc: &ty::AssocItem, tcx: TyCtxt<'_>) -> String {
813 ty::AssocKind::Fn => {
814 // We skip the binder here because the binder would deanonymize all
815 // late-bound regions, and we don't want method signatures to show up
816 // `as for<'r> fn(&'r MyType)`. Pretty-printing handles late-bound
817 // regions just fine, showing `fn(&MyType)`.
820 tcx.fn_sig(assoc.def_id).skip_binder(),
822 tcx.predicates_of(assoc.def_id),
826 ty::AssocKind::Type => format!("type {} = Type;", assoc.name),
827 ty::AssocKind::Const => {
828 let ty = tcx.type_of(assoc.def_id);
829 let val = expr::ty_kind_suggestion(ty).unwrap_or("value");
830 format!("const {}: {} = {};", assoc.name, ty, val)
835 /// Emit an error when encountering two or more variants in a transparent enum.
836 fn bad_variant_count<'tcx>(tcx: TyCtxt<'tcx>, adt: ty::AdtDef<'tcx>, sp: Span, did: DefId) {
837 let variant_spans: Vec<_> = adt
840 .map(|variant| tcx.hir().span_if_local(variant.def_id).unwrap())
842 let msg = format!("needs exactly one variant, but has {}", adt.variants().len(),);
843 let mut err = struct_span_err!(tcx.sess, sp, E0731, "transparent enum {msg}");
844 err.span_label(sp, &msg);
845 if let [start @ .., end] = &*variant_spans {
846 for variant_span in start {
847 err.span_label(*variant_span, "");
849 err.span_label(*end, &format!("too many variants in `{}`", tcx.def_path_str(did)));
854 /// Emit an error when encountering two or more non-zero-sized fields in a transparent
856 fn bad_non_zero_sized_fields<'tcx>(
858 adt: ty::AdtDef<'tcx>,
860 field_spans: impl Iterator<Item = Span>,
863 let msg = format!("needs at most one non-zero-sized field, but has {field_count}");
864 let mut err = struct_span_err!(
868 "{}transparent {} {}",
869 if adt.is_enum() { "the variant of a " } else { "" },
873 err.span_label(sp, &msg);
874 for sp in field_spans {
875 err.span_label(sp, "this field is non-zero-sized");
880 fn report_unexpected_variant_res(tcx: TyCtxt<'_>, res: Res, span: Span) {
885 "expected unit struct, unit variant or constant, found {}{}",
889 .span_to_snippet(span)
890 .map_or_else(|_| String::new(), |s| format!(" `{s}`",)),
895 /// Controls whether the arguments are tupled. This is used for the call
898 /// Tupling means that all call-side arguments are packed into a tuple and
899 /// passed as a single parameter. For example, if tupling is enabled, this
902 /// fn f(x: (isize, isize)) {}
904 /// Can be called as:
905 /// ```ignore UNSOLVED (can this be done in user code?)
906 /// # fn f(x: (isize, isize)) {}
911 /// # fn f(x: (isize, isize)) {}
914 #[derive(Clone, Eq, PartialEq)]
915 enum TupleArgumentsFlag {
920 /// A wrapper for `InferCtxt`'s `in_progress_typeck_results` field.
921 #[derive(Copy, Clone)]
922 struct MaybeInProgressTables<'a, 'tcx> {
923 maybe_typeck_results: Option<&'a RefCell<ty::TypeckResults<'tcx>>>,
926 impl<'a, 'tcx> MaybeInProgressTables<'a, 'tcx> {
927 fn borrow(self) -> Ref<'a, ty::TypeckResults<'tcx>> {
928 match self.maybe_typeck_results {
929 Some(typeck_results) => typeck_results.borrow(),
931 "MaybeInProgressTables: inh/fcx.typeck_results.borrow() with no typeck results"
936 fn borrow_mut(self) -> RefMut<'a, ty::TypeckResults<'tcx>> {
937 match self.maybe_typeck_results {
938 Some(typeck_results) => typeck_results.borrow_mut(),
940 "MaybeInProgressTables: inh/fcx.typeck_results.borrow_mut() with no typeck results"
946 fn typeck_item_bodies(tcx: TyCtxt<'_>, (): ()) {
947 tcx.hir().par_body_owners(|body_owner_def_id| tcx.ensure().typeck(body_owner_def_id));
950 fn fatally_break_rust(sess: &Session) {
951 let handler = sess.diagnostic();
952 handler.span_bug_no_panic(
954 "It looks like you're trying to break rust; would you like some ICE?",
956 handler.note_without_error("the compiler expectedly panicked. this is a feature.");
957 handler.note_without_error(
958 "we would appreciate a joke overview: \
959 https://github.com/rust-lang/rust/issues/43162#issuecomment-320764675",
961 handler.note_without_error(&format!(
962 "rustc {} running on {}",
963 option_env!("CFG_VERSION").unwrap_or("unknown_version"),
964 config::host_triple(),
968 fn potentially_plural_count(count: usize, word: &str) -> String {
969 format!("{} {}{}", count, word, pluralize!(count))
972 fn has_expected_num_generic_args<'tcx>(
974 trait_did: Option<DefId>,
977 trait_did.map_or(true, |trait_did| {
978 let generics = tcx.generics_of(trait_did);
979 generics.count() == expected + if generics.has_self { 1 } else { 0 }
983 /// Suggests calling the constructor of a tuple struct or enum variant
985 /// * `snippet` - The snippet of code that references the constructor
986 /// * `span` - The span of the snippet
987 /// * `params` - The number of parameters the constructor accepts
988 /// * `err` - A mutable diagnostic builder to add the suggestion to
989 fn suggest_call_constructor<G: EmissionGuarantee>(
993 err: &mut DiagnosticBuilder<'_, G>,
995 // Note: tuple-structs don't have named fields, so just use placeholders
996 let args = vec!["_"; params].join(", ");
997 let applicable = if params > 0 {
998 Applicability::HasPlaceholders
1000 // When n = 0, it's an empty-tuple struct/enum variant
1001 // so we trivially know how to construct it
1002 Applicability::MachineApplicable
1004 let kind = match kind {
1005 CtorOf::Struct => "a struct",
1006 CtorOf::Variant => "an enum variant",
1008 err.span_label(span, &format!("this is the constructor of {kind}"));
1009 err.multipart_suggestion(
1010 "call the constructor",
1011 vec![(span.shrink_to_lo(), "(".to_string()), (span.shrink_to_hi(), format!(")({args})"))],