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 where 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;
95 use check::{check_abi, check_fn, check_mod_item_types};
96 pub use diverges::Diverges;
97 pub use expectation::Expectation;
99 pub use inherited::{Inherited, InheritedBuilder};
101 use crate::astconv::AstConv;
102 use crate::check::gather_locals::GatherLocalsVisitor;
103 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
105 pluralize, struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, MultiSpan,
107 use rustc_hir as hir;
108 use rustc_hir::def::Res;
109 use rustc_hir::def_id::{DefId, LocalDefId};
110 use rustc_hir::intravisit::Visitor;
111 use rustc_hir::{HirIdMap, ImplicitSelfKind, Node};
112 use rustc_index::bit_set::BitSet;
113 use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
114 use rustc_middle::ty::query::Providers;
115 use rustc_middle::ty::subst::{InternalSubsts, Subst, SubstsRef};
116 use rustc_middle::ty::{self, Ty, TyCtxt, UserType};
117 use rustc_session::config;
118 use rustc_session::parse::feature_err;
119 use rustc_session::Session;
120 use rustc_span::source_map::DUMMY_SP;
121 use rustc_span::symbol::{kw, Ident};
122 use rustc_span::{self, BytePos, Span, Symbol};
123 use rustc_target::abi::VariantIdx;
124 use rustc_target::spec::abi::Abi;
125 use rustc_trait_selection::traits;
126 use rustc_trait_selection::traits::error_reporting::recursive_type_with_infinite_size_error;
127 use rustc_trait_selection::traits::error_reporting::suggestions::ReturnsVisitor;
128 use std::cell::RefCell;
129 use std::num::NonZeroU32;
131 use crate::require_c_abi_if_c_variadic;
132 use crate::util::common::indenter;
134 use self::coercion::DynamicCoerceMany;
135 use self::region::region_scope_tree;
136 pub use self::Expectation::*;
139 macro_rules! type_error_struct {
140 ($session:expr, $span:expr, $typ:expr, $code:ident, $($message:tt)*) => ({
141 let mut err = rustc_errors::struct_span_err!($session, $span, $code, $($message)*);
143 if $typ.references_error() {
144 err.downgrade_to_delayed_bug();
151 /// The type of a local binding, including the revealed type for anon types.
152 #[derive(Copy, Clone, Debug)]
153 pub struct LocalTy<'tcx> {
155 revealed_ty: Ty<'tcx>,
158 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
165 fn maybe_mut_place(m: hir::Mutability) -> Self {
167 hir::Mutability::Mut => Needs::MutPlace,
168 hir::Mutability::Not => Needs::None,
173 #[derive(Copy, Clone)]
174 pub struct UnsafetyState {
176 pub unsafety: hir::Unsafety,
181 pub fn function(unsafety: hir::Unsafety, def: hir::HirId) -> UnsafetyState {
182 UnsafetyState { def, unsafety, from_fn: true }
185 pub fn recurse(self, blk: &hir::Block<'_>) -> UnsafetyState {
186 use hir::BlockCheckMode;
187 match self.unsafety {
188 // If this unsafe, then if the outer function was already marked as
189 // unsafe we shouldn't attribute the unsafe'ness to the block. This
190 // way the block can be warned about instead of ignoring this
191 // extraneous block (functions are never warned about).
192 hir::Unsafety::Unsafe if self.from_fn => self,
195 let (unsafety, def) = match blk.rules {
196 BlockCheckMode::UnsafeBlock(..) => (hir::Unsafety::Unsafe, blk.hir_id),
197 BlockCheckMode::DefaultBlock => (unsafety, self.def),
199 UnsafetyState { def, unsafety, from_fn: false }
205 #[derive(Debug, Copy, Clone)]
211 pub struct BreakableCtxt<'tcx> {
214 // this is `null` for loops where break with a value is illegal,
215 // such as `while`, `for`, and `while let`
216 coerce: Option<DynamicCoerceMany<'tcx>>,
219 pub struct EnclosingBreakables<'tcx> {
220 stack: Vec<BreakableCtxt<'tcx>>,
221 by_id: HirIdMap<usize>,
224 impl<'tcx> EnclosingBreakables<'tcx> {
225 fn find_breakable(&mut self, target_id: hir::HirId) -> &mut BreakableCtxt<'tcx> {
226 self.opt_find_breakable(target_id).unwrap_or_else(|| {
227 bug!("could not find enclosing breakable with id {}", target_id);
231 fn opt_find_breakable(&mut self, target_id: hir::HirId) -> Option<&mut BreakableCtxt<'tcx>> {
232 match self.by_id.get(&target_id) {
233 Some(ix) => Some(&mut self.stack[*ix]),
239 pub fn provide(providers: &mut Providers) {
240 method::provide(providers);
241 wfcheck::provide(providers);
242 *providers = Providers {
246 diagnostic_only_typeck,
250 check_mod_item_types,
256 fn adt_destructor(tcx: TyCtxt<'_>, def_id: DefId) -> Option<ty::Destructor> {
257 tcx.calculate_dtor(def_id, dropck::check_drop_impl)
260 /// If this `DefId` is a "primary tables entry", returns
261 /// `Some((body_id, body_ty, fn_sig))`. Otherwise, returns `None`.
263 /// If this function returns `Some`, then `typeck_results(def_id)` will
264 /// succeed; if it returns `None`, then `typeck_results(def_id)` may or
265 /// may not succeed. In some cases where this function returns `None`
266 /// (notably closures), `typeck_results(def_id)` would wind up
267 /// redirecting to the owning function.
271 ) -> Option<(hir::BodyId, Option<&hir::Ty<'_>>, Option<&hir::FnSig<'_>>)> {
272 match tcx.hir().get(id) {
273 Node::Item(item) => match item.kind {
274 hir::ItemKind::Const(ty, body) | hir::ItemKind::Static(ty, _, body) => {
275 Some((body, Some(ty), None))
277 hir::ItemKind::Fn(ref sig, .., body) => Some((body, None, Some(sig))),
280 Node::TraitItem(item) => match item.kind {
281 hir::TraitItemKind::Const(ty, Some(body)) => Some((body, Some(ty), None)),
282 hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Provided(body)) => {
283 Some((body, None, Some(sig)))
287 Node::ImplItem(item) => match item.kind {
288 hir::ImplItemKind::Const(ty, body) => Some((body, Some(ty), None)),
289 hir::ImplItemKind::Fn(ref sig, body) => Some((body, None, Some(sig))),
292 Node::AnonConst(constant) => Some((constant.body, None, None)),
297 fn has_typeck_results(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
298 // Closures' typeck results come from their outermost function,
299 // as they are part of the same "inference environment".
300 let typeck_root_def_id = tcx.typeck_root_def_id(def_id);
301 if typeck_root_def_id != def_id {
302 return tcx.has_typeck_results(typeck_root_def_id);
305 if let Some(def_id) = def_id.as_local() {
306 let id = tcx.hir().local_def_id_to_hir_id(def_id);
307 primary_body_of(tcx, id).is_some()
313 fn used_trait_imports(tcx: TyCtxt<'_>, def_id: LocalDefId) -> &FxHashSet<LocalDefId> {
314 &*tcx.typeck(def_id).used_trait_imports
317 fn typeck_const_arg<'tcx>(
319 (did, param_did): (LocalDefId, DefId),
320 ) -> &ty::TypeckResults<'tcx> {
321 let fallback = move || tcx.type_of(param_did);
322 typeck_with_fallback(tcx, did, fallback)
325 fn typeck<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &ty::TypeckResults<'tcx> {
326 if let Some(param_did) = tcx.opt_const_param_of(def_id) {
327 tcx.typeck_const_arg((def_id, param_did))
329 let fallback = move || tcx.type_of(def_id.to_def_id());
330 typeck_with_fallback(tcx, def_id, fallback)
334 /// Used only to get `TypeckResults` for type inference during error recovery.
335 /// Currently only used for type inference of `static`s and `const`s to avoid type cycle errors.
336 fn diagnostic_only_typeck<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &ty::TypeckResults<'tcx> {
337 let fallback = move || {
338 let span = tcx.hir().span(tcx.hir().local_def_id_to_hir_id(def_id));
339 tcx.ty_error_with_message(span, "diagnostic only typeck table used")
341 typeck_with_fallback(tcx, def_id, fallback)
344 #[instrument(skip(tcx, fallback))]
345 fn typeck_with_fallback<'tcx>(
348 fallback: impl Fn() -> Ty<'tcx> + 'tcx,
349 ) -> &'tcx ty::TypeckResults<'tcx> {
350 // Closures' typeck results come from their outermost function,
351 // as they are part of the same "inference environment".
352 let typeck_root_def_id = tcx.typeck_root_def_id(def_id.to_def_id()).expect_local();
353 if typeck_root_def_id != def_id {
354 return tcx.typeck(typeck_root_def_id);
357 let id = tcx.hir().local_def_id_to_hir_id(def_id);
358 let span = tcx.hir().span(id);
360 // Figure out what primary body this item has.
361 let (body_id, body_ty, fn_sig) = primary_body_of(tcx, id).unwrap_or_else(|| {
362 span_bug!(span, "can't type-check body of {:?}", def_id);
364 let body = tcx.hir().body(body_id);
366 let typeck_results = Inherited::build(tcx, def_id).enter(|inh| {
367 let param_env = tcx.param_env(def_id);
368 let fcx = if let Some(hir::FnSig { header, decl, .. }) = fn_sig {
369 let fn_sig = if crate::collect::get_infer_ret_ty(&decl.output).is_some() {
370 let fcx = FnCtxt::new(&inh, param_env, body.value.hir_id);
371 <dyn AstConv<'_>>::ty_of_fn(&fcx, id, header.unsafety, header.abi, decl, None, None)
376 check_abi(tcx, id, span, fn_sig.abi());
378 // Compute the function signature from point of view of inside the fn.
379 let fn_sig = tcx.liberate_late_bound_regions(def_id.to_def_id(), fn_sig);
380 let fn_sig = inh.normalize_associated_types_in(
386 check_fn(&inh, param_env, fn_sig, decl, id, body, None, true).0
388 let fcx = FnCtxt::new(&inh, param_env, body.value.hir_id);
389 let expected_type = body_ty
390 .and_then(|ty| match ty.kind {
391 hir::TyKind::Infer => Some(<dyn AstConv<'_>>::ast_ty_to_ty(&fcx, ty)),
394 .unwrap_or_else(|| match tcx.hir().get(id) {
395 Node::AnonConst(_) => match tcx.hir().get(tcx.hir().get_parent_node(id)) {
396 Node::Expr(&hir::Expr {
397 kind: hir::ExprKind::ConstBlock(ref anon_const),
399 }) if anon_const.hir_id == id => fcx.next_ty_var(TypeVariableOrigin {
400 kind: TypeVariableOriginKind::TypeInference,
404 kind: hir::TyKind::Typeof(ref anon_const), ..
405 }) if anon_const.hir_id == id => fcx.next_ty_var(TypeVariableOrigin {
406 kind: TypeVariableOriginKind::TypeInference,
409 Node::Expr(&hir::Expr { kind: hir::ExprKind::InlineAsm(asm), .. })
410 | Node::Item(&hir::Item { kind: hir::ItemKind::GlobalAsm(asm), .. }) => {
414 .filter_map(|(op, _op_sp)| match op {
415 hir::InlineAsmOperand::Const { anon_const }
416 if anon_const.hir_id == id =>
418 // Inline assembly constants must be integers.
419 Some(fcx.next_int_var())
421 hir::InlineAsmOperand::SymFn { anon_const }
422 if anon_const.hir_id == id =>
424 Some(fcx.next_ty_var(TypeVariableOrigin {
425 kind: TypeVariableOriginKind::MiscVariable,
432 operand_ty.unwrap_or_else(fallback)
439 let expected_type = fcx.normalize_associated_types_in(body.value.span, expected_type);
440 fcx.require_type_is_sized(expected_type, body.value.span, traits::ConstSized);
442 // Gather locals in statics (because of block expressions).
443 GatherLocalsVisitor::new(&fcx).visit_body(body);
445 fcx.check_expr_coercable_to_type(&body.value, expected_type, None);
447 fcx.write_ty(id, expected_type);
452 let fallback_has_occurred = fcx.type_inference_fallback();
454 // Even though coercion casts provide type hints, we check casts after fallback for
455 // backwards compatibility. This makes fallback a stronger type hint than a cast coercion.
457 fcx.select_obligations_where_possible(fallback_has_occurred, |_| {});
459 // Closure and generator analysis may run after fallback
460 // because they don't constrain other type variables.
461 fcx.closure_analyze(body);
462 assert!(fcx.deferred_call_resolutions.borrow().is_empty());
463 // Before the generator analysis, temporary scopes shall be marked to provide more
464 // precise information on types to be captured.
465 fcx.resolve_rvalue_scopes(def_id.to_def_id());
466 fcx.resolve_generator_interiors(def_id.to_def_id());
468 fcx.select_all_obligations_or_error();
470 if !fcx.infcx.is_tainted_by_errors() {
471 fcx.check_transmutes();
476 fcx.infcx.skip_region_resolution();
478 fcx.resolve_type_vars_in_body(body)
481 // Consistency check our TypeckResults instance can hold all ItemLocalIds
482 // it will need to hold.
483 assert_eq!(typeck_results.hir_owner, id.owner);
488 /// When `check_fn` is invoked on a generator (i.e., a body that
489 /// includes yield), it returns back some information about the yield
491 struct GeneratorTypes<'tcx> {
492 /// Type of generator argument / values returned by `yield`.
495 /// Type of value that is yielded.
498 /// Types that are captured (see `GeneratorInterior` for more).
501 /// Indicates if the generator is movable or static (immovable).
502 movability: hir::Movability,
505 /// Given a `DefId` for an opaque type in return position, find its parent item's return
507 fn get_owner_return_paths<'tcx>(
510 ) -> Option<(LocalDefId, ReturnsVisitor<'tcx>)> {
511 let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
512 let parent_id = tcx.hir().get_parent_item(hir_id);
513 tcx.hir().find_by_def_id(parent_id).and_then(|node| node.body_id()).map(|body_id| {
514 let body = tcx.hir().body(body_id);
515 let mut visitor = ReturnsVisitor::default();
516 visitor.visit_body(body);
521 // Forbid defining intrinsics in Rust code,
522 // as they must always be defined by the compiler.
523 fn fn_maybe_err(tcx: TyCtxt<'_>, sp: Span, abi: Abi) {
524 if let Abi::RustIntrinsic | Abi::PlatformIntrinsic = abi {
525 tcx.sess.span_err(sp, "intrinsic must be in `extern \"rust-intrinsic\" { ... }` block");
529 fn maybe_check_static_with_link_section(tcx: TyCtxt<'_>, id: LocalDefId) {
530 // Only restricted on wasm target for now
531 if !tcx.sess.target.is_like_wasm {
535 // If `#[link_section]` is missing, then nothing to verify
536 let attrs = tcx.codegen_fn_attrs(id);
537 if attrs.link_section.is_none() {
541 // For the wasm32 target statics with `#[link_section]` are placed into custom
542 // sections of the final output file, but this isn't link custom sections of
543 // other executable formats. Namely we can only embed a list of bytes,
544 // nothing with provenance (pointers to anything else). If any provenance
545 // show up, reject it here.
546 // `#[link_section]` may contain arbitrary, or even undefined bytes, but it is
547 // the consumer's responsibility to ensure all bytes that have been read
548 // have defined values.
549 if let Ok(alloc) = tcx.eval_static_initializer(id.to_def_id())
550 && alloc.inner().provenance().len() != 0
552 let msg = "statics with a custom `#[link_section]` must be a \
553 simple list of bytes on the wasm target with no \
554 extra levels of indirection such as references";
555 tcx.sess.span_err(tcx.def_span(id), msg);
559 fn report_forbidden_specialization(
561 impl_item: &hir::ImplItemRef,
564 let mut err = struct_span_err!(
568 "`{}` specializes an item from a parent `impl`, but \
569 that item is not marked `default`",
572 err.span_label(impl_item.span, format!("cannot specialize default item `{}`", impl_item.ident));
574 match tcx.span_of_impl(parent_impl) {
576 err.span_label(span, "parent `impl` is here");
578 "to specialize, `{}` in the parent `impl` must be marked `default`",
583 err.note(&format!("parent implementation is in crate `{cname}`"));
590 fn missing_items_err(
593 missing_items: &[&ty::AssocItem],
594 full_impl_span: Span,
596 let missing_items_msg = missing_items
598 .map(|trait_item| trait_item.name.to_string())
602 let mut err = struct_span_err!(
606 "not all trait items implemented, missing: `{missing_items_msg}`",
608 err.span_label(impl_span, format!("missing `{missing_items_msg}` in implementation"));
610 // `Span` before impl block closing brace.
611 let hi = full_impl_span.hi() - BytePos(1);
612 // Point at the place right before the closing brace of the relevant `impl` to suggest
613 // adding the associated item at the end of its body.
614 let sugg_sp = full_impl_span.with_lo(hi).with_hi(hi);
615 // Obtain the level of indentation ending in `sugg_sp`.
617 tcx.sess.source_map().indentation_before(sugg_sp).unwrap_or_else(|| String::new());
619 for trait_item in missing_items {
620 let snippet = suggestion_signature(trait_item, tcx);
621 let code = format!("{}{}\n{}", padding, snippet, padding);
622 let msg = format!("implement the missing item: `{snippet}`");
623 let appl = Applicability::HasPlaceholders;
624 if let Some(span) = tcx.hir().span_if_local(trait_item.def_id) {
625 err.span_label(span, format!("`{}` from trait", trait_item.name));
626 err.tool_only_span_suggestion(sugg_sp, &msg, code, appl);
628 err.span_suggestion_hidden(sugg_sp, &msg, code, appl);
634 fn missing_items_must_implement_one_of_err(
637 missing_items: &[Ident],
638 annotation_span: Option<Span>,
640 let missing_items_msg =
641 missing_items.iter().map(Ident::to_string).collect::<Vec<_>>().join("`, `");
643 let mut err = struct_span_err!(
647 "not all trait items implemented, missing one of: `{missing_items_msg}`",
649 err.span_label(impl_span, format!("missing one of `{missing_items_msg}` in implementation"));
651 if let Some(annotation_span) = annotation_span {
652 err.span_note(annotation_span, "required because of this annotation");
658 fn default_body_is_unstable(
663 reason: Option<Symbol>,
664 issue: Option<NonZeroU32>,
666 let missing_item_name = &tcx.associated_item(item_did).name;
667 let use_of_unstable_library_feature_note = match reason {
668 Some(r) => format!("use of unstable library feature '{feature}': {r}"),
669 None => format!("use of unstable library feature '{feature}'"),
672 let mut err = struct_span_err!(
676 "not all trait items implemented, missing: `{missing_item_name}`",
678 err.note(format!("default implementation of `{missing_item_name}` is unstable"));
679 err.note(use_of_unstable_library_feature_note);
680 rustc_session::parse::add_feature_diagnostics_for_issue(
682 &tcx.sess.parse_sess,
684 rustc_feature::GateIssue::Library(issue),
689 /// Re-sugar `ty::GenericPredicates` in a way suitable to be used in structured suggestions.
690 fn bounds_from_generic_predicates<'tcx>(
692 predicates: ty::GenericPredicates<'tcx>,
693 ) -> (String, String) {
694 let mut types: FxHashMap<Ty<'tcx>, Vec<DefId>> = FxHashMap::default();
695 let mut projections = vec![];
696 for (predicate, _) in predicates.predicates {
697 debug!("predicate {:?}", predicate);
698 let bound_predicate = predicate.kind();
699 match bound_predicate.skip_binder() {
700 ty::PredicateKind::Trait(trait_predicate) => {
701 let entry = types.entry(trait_predicate.self_ty()).or_default();
702 let def_id = trait_predicate.def_id();
703 if Some(def_id) != tcx.lang_items().sized_trait() {
704 // Type params are `Sized` by default, do not add that restriction to the list
705 // if it is a positive requirement.
706 entry.push(trait_predicate.def_id());
709 ty::PredicateKind::Projection(projection_pred) => {
710 projections.push(bound_predicate.rebind(projection_pred));
715 let generics = if types.is_empty() {
722 .filter_map(|t| match t.kind() {
723 ty::Param(_) => Some(t.to_string()),
724 // Avoid suggesting the following:
725 // fn foo<T, <T as Trait>::Bar>(_: T) where T: Trait, <T as Trait>::Bar: Other {}
732 let mut where_clauses = vec![];
733 for (ty, bounds) in types {
735 .extend(bounds.into_iter().map(|bound| format!("{}: {}", ty, tcx.def_path_str(bound))));
737 for projection in &projections {
738 let p = projection.skip_binder();
739 // FIXME: this is not currently supported syntax, we should be looking at the `types` and
740 // insert the associated types where they correspond, but for now let's be "lazy" and
741 // propose this instead of the following valid resugaring:
742 // `T: Trait, Trait::Assoc = K` → `T: Trait<Assoc = K>`
743 where_clauses.push(format!(
745 tcx.def_path_str(p.projection_ty.item_def_id),
749 let where_clauses = if where_clauses.is_empty() {
752 format!(" where {}", where_clauses.join(", "))
754 (generics, where_clauses)
757 /// Return placeholder code for the given function.
758 fn fn_sig_suggestion<'tcx>(
760 sig: ty::FnSig<'tcx>,
762 predicates: ty::GenericPredicates<'tcx>,
763 assoc: &ty::AssocItem,
770 Some(match ty.kind() {
771 ty::Param(_) if assoc.fn_has_self_parameter && i == 0 => "self".to_string(),
772 ty::Ref(reg, ref_ty, mutability) if i == 0 => {
773 let reg = format!("{reg} ");
774 let reg = match ®[..] {
778 if assoc.fn_has_self_parameter {
779 match ref_ty.kind() {
780 ty::Param(param) if param.name == kw::SelfUpper => {
781 format!("&{}{}self", reg, mutability.prefix_str())
784 _ => format!("self: {ty}"),
791 if assoc.fn_has_self_parameter && i == 0 {
792 format!("self: {ty}")
799 .chain(std::iter::once(if sig.c_variadic { Some("...".to_string()) } else { None }))
801 .collect::<Vec<String>>()
803 let output = sig.output();
804 let output = if !output.is_unit() { format!(" -> {output}") } else { String::new() };
806 let unsafety = sig.unsafety.prefix_str();
807 let (generics, where_clauses) = bounds_from_generic_predicates(tcx, predicates);
809 // FIXME: this is not entirely correct, as the lifetimes from borrowed params will
810 // not be present in the `fn` definition, not will we account for renamed
811 // lifetimes between the `impl` and the `trait`, but this should be good enough to
812 // fill in a significant portion of the missing code, and other subsequent
813 // suggestions can help the user fix the code.
814 format!("{unsafety}fn {ident}{generics}({args}){output}{where_clauses} {{ todo!() }}")
817 /// Return placeholder code for the given associated item.
818 /// Similar to `ty::AssocItem::suggestion`, but appropriate for use as the code snippet of a
819 /// structured suggestion.
820 fn suggestion_signature(assoc: &ty::AssocItem, tcx: TyCtxt<'_>) -> String {
822 ty::AssocKind::Fn => {
823 // We skip the binder here because the binder would deanonymize all
824 // late-bound regions, and we don't want method signatures to show up
825 // `as for<'r> fn(&'r MyType)`. Pretty-printing handles late-bound
826 // regions just fine, showing `fn(&MyType)`.
829 tcx.fn_sig(assoc.def_id).skip_binder(),
831 tcx.predicates_of(assoc.def_id),
835 ty::AssocKind::Type => format!("type {} = Type;", assoc.name),
836 ty::AssocKind::Const => {
837 let ty = tcx.type_of(assoc.def_id);
838 let val = expr::ty_kind_suggestion(ty).unwrap_or("value");
839 format!("const {}: {} = {};", assoc.name, ty, val)
844 /// Emit an error when encountering two or more variants in a transparent enum.
845 fn bad_variant_count<'tcx>(tcx: TyCtxt<'tcx>, adt: ty::AdtDef<'tcx>, sp: Span, did: DefId) {
846 let variant_spans: Vec<_> = adt
849 .map(|variant| tcx.hir().span_if_local(variant.def_id).unwrap())
851 let msg = format!("needs exactly one variant, but has {}", adt.variants().len(),);
852 let mut err = struct_span_err!(tcx.sess, sp, E0731, "transparent enum {msg}");
853 err.span_label(sp, &msg);
854 if let [start @ .., end] = &*variant_spans {
855 for variant_span in start {
856 err.span_label(*variant_span, "");
858 err.span_label(*end, &format!("too many variants in `{}`", tcx.def_path_str(did)));
863 /// Emit an error when encountering two or more non-zero-sized fields in a transparent
865 fn bad_non_zero_sized_fields<'tcx>(
867 adt: ty::AdtDef<'tcx>,
869 field_spans: impl Iterator<Item = Span>,
872 let msg = format!("needs at most one non-zero-sized field, but has {field_count}");
873 let mut err = struct_span_err!(
877 "{}transparent {} {}",
878 if adt.is_enum() { "the variant of a " } else { "" },
882 err.span_label(sp, &msg);
883 for sp in field_spans {
884 err.span_label(sp, "this field is non-zero-sized");
889 fn report_unexpected_variant_res(tcx: TyCtxt<'_>, res: Res, qpath: &hir::QPath<'_>, span: Span) {
894 "expected unit struct, unit variant or constant, found {} `{}`",
896 rustc_hir_pretty::qpath_to_string(qpath),
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 fn typeck_item_bodies(tcx: TyCtxt<'_>, (): ()) {
927 tcx.hir().par_body_owners(|body_owner_def_id| tcx.ensure().typeck(body_owner_def_id));
930 fn fatally_break_rust(sess: &Session) {
931 let handler = sess.diagnostic();
932 handler.span_bug_no_panic(
934 "It looks like you're trying to break rust; would you like some ICE?",
936 handler.note_without_error("the compiler expectedly panicked. this is a feature.");
937 handler.note_without_error(
938 "we would appreciate a joke overview: \
939 https://github.com/rust-lang/rust/issues/43162#issuecomment-320764675",
941 handler.note_without_error(&format!(
942 "rustc {} running on {}",
943 option_env!("CFG_VERSION").unwrap_or("unknown_version"),
944 config::host_triple(),
948 fn potentially_plural_count(count: usize, word: &str) -> String {
949 format!("{} {}{}", count, word, pluralize!(count))
952 fn has_expected_num_generic_args<'tcx>(
954 trait_did: Option<DefId>,
957 trait_did.map_or(true, |trait_did| {
958 let generics = tcx.generics_of(trait_did);
959 generics.count() == expected + if generics.has_self { 1 } else { 0 }