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::{self, Ty, TyCtxt, UserType};
116 use rustc_middle::ty::{InternalSubsts, SubstsRef};
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::compare_method::collect_trait_impl_trait_tys;
136 use self::region::region_scope_tree;
137 pub use self::Expectation::*;
140 macro_rules! type_error_struct {
141 ($session:expr, $span:expr, $typ:expr, $code:ident, $($message:tt)*) => ({
142 let mut err = rustc_errors::struct_span_err!($session, $span, $code, $($message)*);
144 if $typ.references_error() {
145 err.downgrade_to_delayed_bug();
152 /// The type of a local binding, including the revealed type for anon types.
153 #[derive(Copy, Clone, Debug)]
154 pub struct LocalTy<'tcx> {
156 revealed_ty: Ty<'tcx>,
159 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
166 fn maybe_mut_place(m: hir::Mutability) -> Self {
168 hir::Mutability::Mut => Needs::MutPlace,
169 hir::Mutability::Not => Needs::None,
174 #[derive(Copy, Clone)]
175 pub struct UnsafetyState {
177 pub unsafety: hir::Unsafety,
182 pub fn function(unsafety: hir::Unsafety, def: hir::HirId) -> UnsafetyState {
183 UnsafetyState { def, unsafety, from_fn: true }
186 pub fn recurse(self, blk: &hir::Block<'_>) -> UnsafetyState {
187 use hir::BlockCheckMode;
188 match self.unsafety {
189 // If this unsafe, then if the outer function was already marked as
190 // unsafe we shouldn't attribute the unsafe'ness to the block. This
191 // way the block can be warned about instead of ignoring this
192 // extraneous block (functions are never warned about).
193 hir::Unsafety::Unsafe if self.from_fn => self,
196 let (unsafety, def) = match blk.rules {
197 BlockCheckMode::UnsafeBlock(..) => (hir::Unsafety::Unsafe, blk.hir_id),
198 BlockCheckMode::DefaultBlock => (unsafety, self.def),
200 UnsafetyState { def, unsafety, from_fn: false }
206 #[derive(Debug, Copy, Clone)]
212 pub struct BreakableCtxt<'tcx> {
215 // this is `null` for loops where break with a value is illegal,
216 // such as `while`, `for`, and `while let`
217 coerce: Option<DynamicCoerceMany<'tcx>>,
220 pub struct EnclosingBreakables<'tcx> {
221 stack: Vec<BreakableCtxt<'tcx>>,
222 by_id: HirIdMap<usize>,
225 impl<'tcx> EnclosingBreakables<'tcx> {
226 fn find_breakable(&mut self, target_id: hir::HirId) -> &mut BreakableCtxt<'tcx> {
227 self.opt_find_breakable(target_id).unwrap_or_else(|| {
228 bug!("could not find enclosing breakable with id {}", target_id);
232 fn opt_find_breakable(&mut self, target_id: hir::HirId) -> Option<&mut BreakableCtxt<'tcx>> {
233 match self.by_id.get(&target_id) {
234 Some(ix) => Some(&mut self.stack[*ix]),
240 pub fn provide(providers: &mut Providers) {
241 method::provide(providers);
242 wfcheck::provide(providers);
243 *providers = Providers {
247 diagnostic_only_typeck,
251 check_mod_item_types,
253 collect_trait_impl_trait_tys,
254 compare_assoc_const_impl_item_with_trait_item: compare_method::raw_compare_const_impl,
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 fn typeck_with_fallback<'tcx>(
350 fallback: impl Fn() -> Ty<'tcx> + 'tcx,
351 ) -> &'tcx ty::TypeckResults<'tcx> {
352 // Closures' typeck results come from their outermost function,
353 // as they are part of the same "inference environment".
354 let typeck_root_def_id = tcx.typeck_root_def_id(def_id.to_def_id()).expect_local();
355 if typeck_root_def_id != def_id {
356 return tcx.typeck(typeck_root_def_id);
359 let id = tcx.hir().local_def_id_to_hir_id(def_id);
360 let span = tcx.hir().span(id);
362 // Figure out what primary body this item has.
363 let (body_id, body_ty, fn_sig) = primary_body_of(tcx, id).unwrap_or_else(|| {
364 span_bug!(span, "can't type-check body of {:?}", def_id);
366 let body = tcx.hir().body(body_id);
368 let typeck_results = Inherited::build(tcx, def_id).enter(|inh| {
369 let param_env = tcx.param_env(def_id);
370 let mut fcx = if let Some(hir::FnSig { header, decl, .. }) = fn_sig {
371 let fn_sig = if crate::collect::get_infer_ret_ty(&decl.output).is_some() {
372 let fcx = FnCtxt::new(&inh, param_env, body.value.hir_id);
373 <dyn AstConv<'_>>::ty_of_fn(&fcx, id, header.unsafety, header.abi, decl, None, None)
378 check_abi(tcx, id, span, fn_sig.abi());
380 // Compute the function signature from point of view of inside the fn.
381 let fn_sig = tcx.liberate_late_bound_regions(def_id.to_def_id(), fn_sig);
382 let fn_sig = inh.normalize_associated_types_in(
388 check_fn(&inh, param_env, fn_sig, decl, id, body, None, true).0
390 let fcx = FnCtxt::new(&inh, param_env, body.value.hir_id);
391 let expected_type = body_ty
392 .and_then(|ty| match ty.kind {
393 hir::TyKind::Infer => Some(<dyn AstConv<'_>>::ast_ty_to_ty(&fcx, ty)),
396 .unwrap_or_else(|| match tcx.hir().get(id) {
397 Node::AnonConst(_) => match tcx.hir().get(tcx.hir().get_parent_node(id)) {
398 Node::Expr(&hir::Expr {
399 kind: hir::ExprKind::ConstBlock(ref anon_const),
401 }) if anon_const.hir_id == id => fcx.next_ty_var(TypeVariableOrigin {
402 kind: TypeVariableOriginKind::TypeInference,
406 kind: hir::TyKind::Typeof(ref anon_const), ..
407 }) if anon_const.hir_id == id => fcx.next_ty_var(TypeVariableOrigin {
408 kind: TypeVariableOriginKind::TypeInference,
411 Node::Expr(&hir::Expr { kind: hir::ExprKind::InlineAsm(asm), .. })
412 | Node::Item(&hir::Item { kind: hir::ItemKind::GlobalAsm(asm), .. }) => {
416 .filter_map(|(op, _op_sp)| match op {
417 hir::InlineAsmOperand::Const { anon_const }
418 if anon_const.hir_id == id =>
420 // Inline assembly constants must be integers.
421 Some(fcx.next_int_var())
423 hir::InlineAsmOperand::SymFn { anon_const }
424 if anon_const.hir_id == id =>
426 Some(fcx.next_ty_var(TypeVariableOrigin {
427 kind: TypeVariableOriginKind::MiscVariable,
434 operand_ty.unwrap_or_else(fallback)
441 let expected_type = fcx.normalize_associated_types_in(body.value.span, expected_type);
442 fcx.require_type_is_sized(expected_type, body.value.span, traits::ConstSized);
444 // Gather locals in statics (because of block expressions).
445 GatherLocalsVisitor::new(&fcx).visit_body(body);
447 fcx.check_expr_coercable_to_type(&body.value, expected_type, None);
449 fcx.write_ty(id, expected_type);
454 let fallback_has_occurred = fcx.type_inference_fallback();
456 // Even though coercion casts provide type hints, we check casts after fallback for
457 // backwards compatibility. This makes fallback a stronger type hint than a cast coercion.
459 fcx.select_obligations_where_possible(fallback_has_occurred, |_| {});
461 // Closure and generator analysis may run after fallback
462 // because they don't constrain other type variables.
463 // Closure analysis only runs on closures. Therefore they only need to fulfill non-const predicates (as of now)
464 let prev_constness = fcx.param_env.constness();
465 fcx.param_env = fcx.param_env.without_const();
466 fcx.closure_analyze(body);
467 fcx.param_env = fcx.param_env.with_constness(prev_constness);
468 assert!(fcx.deferred_call_resolutions.borrow().is_empty());
469 // Before the generator analysis, temporary scopes shall be marked to provide more
470 // precise information on types to be captured.
471 fcx.resolve_rvalue_scopes(def_id.to_def_id());
472 fcx.resolve_generator_interiors(def_id.to_def_id());
474 for (ty, span, code) in fcx.deferred_sized_obligations.borrow_mut().drain(..) {
475 let ty = fcx.normalize_ty(span, ty);
476 fcx.require_type_is_sized(ty, span, code);
479 fcx.select_all_obligations_or_error();
481 if !fcx.infcx.is_tainted_by_errors() {
482 fcx.check_transmutes();
487 fcx.infcx.skip_region_resolution();
489 fcx.resolve_type_vars_in_body(body)
492 // Consistency check our TypeckResults instance can hold all ItemLocalIds
493 // it will need to hold.
494 assert_eq!(typeck_results.hir_owner, id.owner);
499 /// When `check_fn` is invoked on a generator (i.e., a body that
500 /// includes yield), it returns back some information about the yield
502 struct GeneratorTypes<'tcx> {
503 /// Type of generator argument / values returned by `yield`.
506 /// Type of value that is yielded.
509 /// Types that are captured (see `GeneratorInterior` for more).
512 /// Indicates if the generator is movable or static (immovable).
513 movability: hir::Movability,
516 /// Given a `DefId` for an opaque type in return position, find its parent item's return
518 fn get_owner_return_paths<'tcx>(
521 ) -> Option<(LocalDefId, ReturnsVisitor<'tcx>)> {
522 let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
523 let parent_id = tcx.hir().get_parent_item(hir_id).def_id;
524 tcx.hir().find_by_def_id(parent_id).and_then(|node| node.body_id()).map(|body_id| {
525 let body = tcx.hir().body(body_id);
526 let mut visitor = ReturnsVisitor::default();
527 visitor.visit_body(body);
532 // Forbid defining intrinsics in Rust code,
533 // as they must always be defined by the compiler.
534 fn fn_maybe_err(tcx: TyCtxt<'_>, sp: Span, abi: Abi) {
535 if let Abi::RustIntrinsic | Abi::PlatformIntrinsic = abi {
536 tcx.sess.span_err(sp, "intrinsic must be in `extern \"rust-intrinsic\" { ... }` block");
540 fn maybe_check_static_with_link_section(tcx: TyCtxt<'_>, id: LocalDefId) {
541 // Only restricted on wasm target for now
542 if !tcx.sess.target.is_like_wasm {
546 // If `#[link_section]` is missing, then nothing to verify
547 let attrs = tcx.codegen_fn_attrs(id);
548 if attrs.link_section.is_none() {
552 // For the wasm32 target statics with `#[link_section]` are placed into custom
553 // sections of the final output file, but this isn't link custom sections of
554 // other executable formats. Namely we can only embed a list of bytes,
555 // nothing with provenance (pointers to anything else). If any provenance
556 // show up, reject it here.
557 // `#[link_section]` may contain arbitrary, or even undefined bytes, but it is
558 // the consumer's responsibility to ensure all bytes that have been read
559 // have defined values.
560 if let Ok(alloc) = tcx.eval_static_initializer(id.to_def_id())
561 && alloc.inner().provenance().len() != 0
563 let msg = "statics with a custom `#[link_section]` must be a \
564 simple list of bytes on the wasm target with no \
565 extra levels of indirection such as references";
566 tcx.sess.span_err(tcx.def_span(id), msg);
570 fn report_forbidden_specialization(
572 impl_item: &hir::ImplItemRef,
575 let mut err = struct_span_err!(
579 "`{}` specializes an item from a parent `impl`, but \
580 that item is not marked `default`",
583 err.span_label(impl_item.span, format!("cannot specialize default item `{}`", impl_item.ident));
585 match tcx.span_of_impl(parent_impl) {
587 err.span_label(span, "parent `impl` is here");
589 "to specialize, `{}` in the parent `impl` must be marked `default`",
594 err.note(&format!("parent implementation is in crate `{cname}`"));
601 fn missing_items_err(
604 missing_items: &[&ty::AssocItem],
605 full_impl_span: Span,
607 let missing_items_msg = missing_items
609 .map(|trait_item| trait_item.name.to_string())
613 let mut err = struct_span_err!(
617 "not all trait items implemented, missing: `{missing_items_msg}`",
619 err.span_label(impl_span, format!("missing `{missing_items_msg}` in implementation"));
621 // `Span` before impl block closing brace.
622 let hi = full_impl_span.hi() - BytePos(1);
623 // Point at the place right before the closing brace of the relevant `impl` to suggest
624 // adding the associated item at the end of its body.
625 let sugg_sp = full_impl_span.with_lo(hi).with_hi(hi);
626 // Obtain the level of indentation ending in `sugg_sp`.
628 tcx.sess.source_map().indentation_before(sugg_sp).unwrap_or_else(|| String::new());
630 for trait_item in missing_items {
631 let snippet = suggestion_signature(trait_item, tcx);
632 let code = format!("{}{}\n{}", padding, snippet, padding);
633 let msg = format!("implement the missing item: `{snippet}`");
634 let appl = Applicability::HasPlaceholders;
635 if let Some(span) = tcx.hir().span_if_local(trait_item.def_id) {
636 err.span_label(span, format!("`{}` from trait", trait_item.name));
637 err.tool_only_span_suggestion(sugg_sp, &msg, code, appl);
639 err.span_suggestion_hidden(sugg_sp, &msg, code, appl);
645 fn missing_items_must_implement_one_of_err(
648 missing_items: &[Ident],
649 annotation_span: Option<Span>,
651 let missing_items_msg =
652 missing_items.iter().map(Ident::to_string).collect::<Vec<_>>().join("`, `");
654 let mut err = struct_span_err!(
658 "not all trait items implemented, missing one of: `{missing_items_msg}`",
660 err.span_label(impl_span, format!("missing one of `{missing_items_msg}` in implementation"));
662 if let Some(annotation_span) = annotation_span {
663 err.span_note(annotation_span, "required because of this annotation");
669 fn default_body_is_unstable(
674 reason: Option<Symbol>,
675 issue: Option<NonZeroU32>,
677 let missing_item_name = &tcx.associated_item(item_did).name;
678 let use_of_unstable_library_feature_note = match reason {
679 Some(r) => format!("use of unstable library feature '{feature}': {r}"),
680 None => format!("use of unstable library feature '{feature}'"),
683 let mut err = struct_span_err!(
687 "not all trait items implemented, missing: `{missing_item_name}`",
689 err.note(format!("default implementation of `{missing_item_name}` is unstable"));
690 err.note(use_of_unstable_library_feature_note);
691 rustc_session::parse::add_feature_diagnostics_for_issue(
693 &tcx.sess.parse_sess,
695 rustc_feature::GateIssue::Library(issue),
700 /// Re-sugar `ty::GenericPredicates` in a way suitable to be used in structured suggestions.
701 fn bounds_from_generic_predicates<'tcx>(
703 predicates: ty::GenericPredicates<'tcx>,
704 ) -> (String, String) {
705 let mut types: FxHashMap<Ty<'tcx>, Vec<DefId>> = FxHashMap::default();
706 let mut projections = vec![];
707 for (predicate, _) in predicates.predicates {
708 debug!("predicate {:?}", predicate);
709 let bound_predicate = predicate.kind();
710 match bound_predicate.skip_binder() {
711 ty::PredicateKind::Trait(trait_predicate) => {
712 let entry = types.entry(trait_predicate.self_ty()).or_default();
713 let def_id = trait_predicate.def_id();
714 if Some(def_id) != tcx.lang_items().sized_trait() {
715 // Type params are `Sized` by default, do not add that restriction to the list
716 // if it is a positive requirement.
717 entry.push(trait_predicate.def_id());
720 ty::PredicateKind::Projection(projection_pred) => {
721 projections.push(bound_predicate.rebind(projection_pred));
726 let generics = if types.is_empty() {
733 .filter_map(|t| match t.kind() {
734 ty::Param(_) => Some(t.to_string()),
735 // Avoid suggesting the following:
736 // fn foo<T, <T as Trait>::Bar>(_: T) where T: Trait, <T as Trait>::Bar: Other {}
743 let mut where_clauses = vec![];
744 for (ty, bounds) in types {
746 .extend(bounds.into_iter().map(|bound| format!("{}: {}", ty, tcx.def_path_str(bound))));
748 for projection in &projections {
749 let p = projection.skip_binder();
750 // FIXME: this is not currently supported syntax, we should be looking at the `types` and
751 // insert the associated types where they correspond, but for now let's be "lazy" and
752 // propose this instead of the following valid resugaring:
753 // `T: Trait, Trait::Assoc = K` → `T: Trait<Assoc = K>`
754 where_clauses.push(format!(
756 tcx.def_path_str(p.projection_ty.item_def_id),
760 let where_clauses = if where_clauses.is_empty() {
763 format!(" where {}", where_clauses.join(", "))
765 (generics, where_clauses)
768 /// Return placeholder code for the given function.
769 fn fn_sig_suggestion<'tcx>(
771 sig: ty::FnSig<'tcx>,
773 predicates: ty::GenericPredicates<'tcx>,
774 assoc: &ty::AssocItem,
781 Some(match ty.kind() {
782 ty::Param(_) if assoc.fn_has_self_parameter && i == 0 => "self".to_string(),
783 ty::Ref(reg, ref_ty, mutability) if i == 0 => {
784 let reg = format!("{reg} ");
785 let reg = match ®[..] {
789 if assoc.fn_has_self_parameter {
790 match ref_ty.kind() {
791 ty::Param(param) if param.name == kw::SelfUpper => {
792 format!("&{}{}self", reg, mutability.prefix_str())
795 _ => format!("self: {ty}"),
802 if assoc.fn_has_self_parameter && i == 0 {
803 format!("self: {ty}")
810 .chain(std::iter::once(if sig.c_variadic { Some("...".to_string()) } else { None }))
812 .collect::<Vec<String>>()
814 let output = sig.output();
815 let output = if !output.is_unit() { format!(" -> {output}") } else { String::new() };
817 let unsafety = sig.unsafety.prefix_str();
818 let (generics, where_clauses) = bounds_from_generic_predicates(tcx, predicates);
820 // FIXME: this is not entirely correct, as the lifetimes from borrowed params will
821 // not be present in the `fn` definition, not will we account for renamed
822 // lifetimes between the `impl` and the `trait`, but this should be good enough to
823 // fill in a significant portion of the missing code, and other subsequent
824 // suggestions can help the user fix the code.
825 format!("{unsafety}fn {ident}{generics}({args}){output}{where_clauses} {{ todo!() }}")
828 /// Return placeholder code for the given associated item.
829 /// Similar to `ty::AssocItem::suggestion`, but appropriate for use as the code snippet of a
830 /// structured suggestion.
831 fn suggestion_signature(assoc: &ty::AssocItem, tcx: TyCtxt<'_>) -> String {
833 ty::AssocKind::Fn => {
834 // We skip the binder here because the binder would deanonymize all
835 // late-bound regions, and we don't want method signatures to show up
836 // `as for<'r> fn(&'r MyType)`. Pretty-printing handles late-bound
837 // regions just fine, showing `fn(&MyType)`.
840 tcx.fn_sig(assoc.def_id).skip_binder(),
842 tcx.predicates_of(assoc.def_id),
846 ty::AssocKind::Type => format!("type {} = Type;", assoc.name),
847 ty::AssocKind::Const => {
848 let ty = tcx.type_of(assoc.def_id);
849 let val = expr::ty_kind_suggestion(ty).unwrap_or("value");
850 format!("const {}: {} = {};", assoc.name, ty, val)
855 /// Emit an error when encountering two or more variants in a transparent enum.
856 fn bad_variant_count<'tcx>(tcx: TyCtxt<'tcx>, adt: ty::AdtDef<'tcx>, sp: Span, did: DefId) {
857 let variant_spans: Vec<_> = adt
860 .map(|variant| tcx.hir().span_if_local(variant.def_id).unwrap())
862 let msg = format!("needs exactly one variant, but has {}", adt.variants().len(),);
863 let mut err = struct_span_err!(tcx.sess, sp, E0731, "transparent enum {msg}");
864 err.span_label(sp, &msg);
865 if let [start @ .., end] = &*variant_spans {
866 for variant_span in start {
867 err.span_label(*variant_span, "");
869 err.span_label(*end, &format!("too many variants in `{}`", tcx.def_path_str(did)));
874 /// Emit an error when encountering two or more non-zero-sized fields in a transparent
876 fn bad_non_zero_sized_fields<'tcx>(
878 adt: ty::AdtDef<'tcx>,
880 field_spans: impl Iterator<Item = Span>,
883 let msg = format!("needs at most one non-zero-sized field, but has {field_count}");
884 let mut err = struct_span_err!(
888 "{}transparent {} {}",
889 if adt.is_enum() { "the variant of a " } else { "" },
893 err.span_label(sp, &msg);
894 for sp in field_spans {
895 err.span_label(sp, "this field is non-zero-sized");
900 fn report_unexpected_variant_res(tcx: TyCtxt<'_>, res: Res, qpath: &hir::QPath<'_>, span: Span) {
905 "expected unit struct, unit variant or constant, found {} `{}`",
907 rustc_hir_pretty::qpath_to_string(qpath),
912 /// Controls whether the arguments are tupled. This is used for the call
915 /// Tupling means that all call-side arguments are packed into a tuple and
916 /// passed as a single parameter. For example, if tupling is enabled, this
919 /// fn f(x: (isize, isize)) {}
921 /// Can be called as:
922 /// ```ignore UNSOLVED (can this be done in user code?)
923 /// # fn f(x: (isize, isize)) {}
928 /// # fn f(x: (isize, isize)) {}
931 #[derive(Clone, Eq, PartialEq)]
932 enum TupleArgumentsFlag {
937 fn typeck_item_bodies(tcx: TyCtxt<'_>, (): ()) {
938 tcx.hir().par_body_owners(|body_owner_def_id| tcx.ensure().typeck(body_owner_def_id));
941 fn fatally_break_rust(sess: &Session) {
942 let handler = sess.diagnostic();
943 handler.span_bug_no_panic(
945 "It looks like you're trying to break rust; would you like some ICE?",
947 handler.note_without_error("the compiler expectedly panicked. this is a feature.");
948 handler.note_without_error(
949 "we would appreciate a joke overview: \
950 https://github.com/rust-lang/rust/issues/43162#issuecomment-320764675",
952 handler.note_without_error(&format!(
953 "rustc {} running on {}",
954 option_env!("CFG_VERSION").unwrap_or("unknown_version"),
955 config::host_triple(),
959 fn potentially_plural_count(count: usize, word: &str) -> String {
960 format!("{} {}{}", count, word, pluralize!(count))
963 fn has_expected_num_generic_args<'tcx>(
965 trait_did: Option<DefId>,
968 trait_did.map_or(true, |trait_did| {
969 let generics = tcx.generics_of(trait_did);
970 generics.count() == expected + if generics.has_self { 1 } else { 0 }