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;
100 pub use inherited::{Inherited, InheritedBuilder};
102 use crate::astconv::AstConv;
103 use crate::check::gather_locals::GatherLocalsVisitor;
104 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
106 pluralize, struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, MultiSpan,
108 use rustc_hir as hir;
109 use rustc_hir::def::Res;
110 use rustc_hir::def_id::{DefId, LocalDefId};
111 use rustc_hir::intravisit::Visitor;
112 use rustc_hir::{HirIdMap, ImplicitSelfKind, Node};
113 use rustc_index::bit_set::BitSet;
114 use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
115 use rustc_middle::ty::query::Providers;
116 use rustc_middle::ty::subst::{InternalSubsts, Subst, SubstsRef};
117 use rustc_middle::ty::{self, Ty, TyCtxt, UserType};
118 use rustc_session::config;
119 use rustc_session::parse::feature_err;
120 use rustc_session::Session;
121 use rustc_span::source_map::DUMMY_SP;
122 use rustc_span::symbol::{kw, Ident};
123 use rustc_span::{self, BytePos, Span, Symbol};
124 use rustc_target::abi::VariantIdx;
125 use rustc_target::spec::abi::Abi;
126 use rustc_trait_selection::traits;
127 use rustc_trait_selection::traits::error_reporting::recursive_type_with_infinite_size_error;
128 use rustc_trait_selection::traits::error_reporting::suggestions::ReturnsVisitor;
129 use std::cell::RefCell;
130 use std::num::NonZeroU32;
132 use crate::require_c_abi_if_c_variadic;
133 use crate::util::common::indenter;
135 use self::coercion::DynamicCoerceMany;
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,
257 fn adt_destructor(tcx: TyCtxt<'_>, def_id: DefId) -> Option<ty::Destructor> {
258 tcx.calculate_dtor(def_id, dropck::check_drop_impl)
261 /// If this `DefId` is a "primary tables entry", returns
262 /// `Some((body_id, body_ty, fn_sig))`. Otherwise, returns `None`.
264 /// If this function returns `Some`, then `typeck_results(def_id)` will
265 /// succeed; if it returns `None`, then `typeck_results(def_id)` may or
266 /// may not succeed. In some cases where this function returns `None`
267 /// (notably closures), `typeck_results(def_id)` would wind up
268 /// redirecting to the owning function.
272 ) -> Option<(hir::BodyId, Option<&hir::Ty<'_>>, Option<&hir::FnSig<'_>>)> {
273 match tcx.hir().get(id) {
274 Node::Item(item) => match item.kind {
275 hir::ItemKind::Const(ty, body) | hir::ItemKind::Static(ty, _, body) => {
276 Some((body, Some(ty), None))
278 hir::ItemKind::Fn(ref sig, .., body) => Some((body, None, Some(sig))),
281 Node::TraitItem(item) => match item.kind {
282 hir::TraitItemKind::Const(ty, Some(body)) => Some((body, Some(ty), None)),
283 hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Provided(body)) => {
284 Some((body, None, Some(sig)))
288 Node::ImplItem(item) => match item.kind {
289 hir::ImplItemKind::Const(ty, body) => Some((body, Some(ty), None)),
290 hir::ImplItemKind::Fn(ref sig, body) => Some((body, None, Some(sig))),
293 Node::AnonConst(constant) => Some((constant.body, None, None)),
298 fn has_typeck_results(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
299 // Closures' typeck results come from their outermost function,
300 // as they are part of the same "inference environment".
301 let typeck_root_def_id = tcx.typeck_root_def_id(def_id);
302 if typeck_root_def_id != def_id {
303 return tcx.has_typeck_results(typeck_root_def_id);
306 if let Some(def_id) = def_id.as_local() {
307 let id = tcx.hir().local_def_id_to_hir_id(def_id);
308 primary_body_of(tcx, id).is_some()
314 fn used_trait_imports(tcx: TyCtxt<'_>, def_id: LocalDefId) -> &FxHashSet<LocalDefId> {
315 &*tcx.typeck(def_id).used_trait_imports
318 fn typeck_const_arg<'tcx>(
320 (did, param_did): (LocalDefId, DefId),
321 ) -> &ty::TypeckResults<'tcx> {
322 let fallback = move || tcx.type_of(param_did);
323 typeck_with_fallback(tcx, did, fallback)
326 fn typeck<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &ty::TypeckResults<'tcx> {
327 if let Some(param_did) = tcx.opt_const_param_of(def_id) {
328 tcx.typeck_const_arg((def_id, param_did))
330 let fallback = move || tcx.type_of(def_id.to_def_id());
331 typeck_with_fallback(tcx, def_id, fallback)
335 /// Used only to get `TypeckResults` for type inference during error recovery.
336 /// Currently only used for type inference of `static`s and `const`s to avoid type cycle errors.
337 fn diagnostic_only_typeck<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &ty::TypeckResults<'tcx> {
338 let fallback = move || {
339 let span = tcx.hir().span(tcx.hir().local_def_id_to_hir_id(def_id));
340 tcx.ty_error_with_message(span, "diagnostic only typeck table used")
342 typeck_with_fallback(tcx, def_id, fallback)
345 #[instrument(skip(tcx, fallback))]
346 fn typeck_with_fallback<'tcx>(
349 fallback: impl Fn() -> Ty<'tcx> + 'tcx,
350 ) -> &'tcx ty::TypeckResults<'tcx> {
351 // Closures' typeck results come from their outermost function,
352 // as they are part of the same "inference environment".
353 let typeck_root_def_id = tcx.typeck_root_def_id(def_id.to_def_id()).expect_local();
354 if typeck_root_def_id != def_id {
355 return tcx.typeck(typeck_root_def_id);
358 let id = tcx.hir().local_def_id_to_hir_id(def_id);
359 let span = tcx.hir().span(id);
361 // Figure out what primary body this item has.
362 let (body_id, body_ty, fn_sig) = primary_body_of(tcx, id).unwrap_or_else(|| {
363 span_bug!(span, "can't type-check body of {:?}", def_id);
365 let body = tcx.hir().body(body_id);
367 let typeck_results = Inherited::build(tcx, def_id).enter(|inh| {
368 let param_env = tcx.param_env(def_id);
369 let fcx = if let Some(hir::FnSig { header, decl, .. }) = fn_sig {
370 let fn_sig = if crate::collect::get_infer_ret_ty(&decl.output).is_some() {
371 let fcx = FnCtxt::new(&inh, param_env, body.value.hir_id);
372 <dyn AstConv<'_>>::ty_of_fn(&fcx, id, header.unsafety, header.abi, decl, None, None)
377 check_abi(tcx, id, span, fn_sig.abi());
379 // Compute the function signature from point of view of inside the fn.
380 let fn_sig = tcx.liberate_late_bound_regions(def_id.to_def_id(), fn_sig);
381 let fn_sig = inh.normalize_associated_types_in(
387 check_fn(&inh, param_env, fn_sig, decl, id, body, None, true).0
389 let fcx = FnCtxt::new(&inh, param_env, body.value.hir_id);
390 let expected_type = body_ty
391 .and_then(|ty| match ty.kind {
392 hir::TyKind::Infer => Some(<dyn AstConv<'_>>::ast_ty_to_ty(&fcx, ty)),
395 .unwrap_or_else(|| match tcx.hir().get(id) {
396 Node::AnonConst(_) => match tcx.hir().get(tcx.hir().get_parent_node(id)) {
397 Node::Expr(&hir::Expr {
398 kind: hir::ExprKind::ConstBlock(ref anon_const),
400 }) if anon_const.hir_id == id => fcx.next_ty_var(TypeVariableOrigin {
401 kind: TypeVariableOriginKind::TypeInference,
405 kind: hir::TyKind::Typeof(ref anon_const), ..
406 }) if anon_const.hir_id == id => fcx.next_ty_var(TypeVariableOrigin {
407 kind: TypeVariableOriginKind::TypeInference,
410 Node::Expr(&hir::Expr { kind: hir::ExprKind::InlineAsm(asm), .. })
411 | Node::Item(&hir::Item { kind: hir::ItemKind::GlobalAsm(asm), .. }) => {
415 .filter_map(|(op, _op_sp)| match op {
416 hir::InlineAsmOperand::Const { anon_const }
417 if anon_const.hir_id == id =>
419 // Inline assembly constants must be integers.
420 Some(fcx.next_int_var())
422 hir::InlineAsmOperand::SymFn { anon_const }
423 if anon_const.hir_id == id =>
425 Some(fcx.next_ty_var(TypeVariableOrigin {
426 kind: TypeVariableOriginKind::MiscVariable,
433 operand_ty.unwrap_or_else(fallback)
440 let expected_type = fcx.normalize_associated_types_in(body.value.span, expected_type);
441 fcx.require_type_is_sized(expected_type, body.value.span, traits::ConstSized);
443 // Gather locals in statics (because of block expressions).
444 GatherLocalsVisitor::new(&fcx).visit_body(body);
446 fcx.check_expr_coercable_to_type(&body.value, expected_type, None);
448 fcx.write_ty(id, expected_type);
453 let fallback_has_occurred = fcx.type_inference_fallback();
455 // Even though coercion casts provide type hints, we check casts after fallback for
456 // backwards compatibility. This makes fallback a stronger type hint than a cast coercion.
458 fcx.select_obligations_where_possible(fallback_has_occurred, |_| {});
460 // Closure and generator analysis may run after fallback
461 // because they don't constrain other type variables.
462 fcx.closure_analyze(body);
463 assert!(fcx.deferred_call_resolutions.borrow().is_empty());
464 // Before the generator analysis, temporary scopes shall be marked to provide more
465 // precise information on types to be captured.
466 fcx.resolve_rvalue_scopes(def_id.to_def_id());
467 fcx.resolve_generator_interiors(def_id.to_def_id());
469 fcx.select_all_obligations_or_error();
471 if !fcx.infcx.is_tainted_by_errors() {
472 fcx.check_transmutes();
477 fcx.infcx.skip_region_resolution();
479 fcx.resolve_type_vars_in_body(body)
482 // Consistency check our TypeckResults instance can hold all ItemLocalIds
483 // it will need to hold.
484 assert_eq!(typeck_results.hir_owner, id.owner);
489 /// When `check_fn` is invoked on a generator (i.e., a body that
490 /// includes yield), it returns back some information about the yield
492 struct GeneratorTypes<'tcx> {
493 /// Type of generator argument / values returned by `yield`.
496 /// Type of value that is yielded.
499 /// Types that are captured (see `GeneratorInterior` for more).
502 /// Indicates if the generator is movable or static (immovable).
503 movability: hir::Movability,
506 /// Given a `DefId` for an opaque type in return position, find its parent item's return
508 fn get_owner_return_paths<'tcx>(
511 ) -> Option<(LocalDefId, ReturnsVisitor<'tcx>)> {
512 let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
513 let parent_id = tcx.hir().get_parent_item(hir_id);
514 tcx.hir().find_by_def_id(parent_id).and_then(|node| node.body_id()).map(|body_id| {
515 let body = tcx.hir().body(body_id);
516 let mut visitor = ReturnsVisitor::default();
517 visitor.visit_body(body);
522 // Forbid defining intrinsics in Rust code,
523 // as they must always be defined by the compiler.
524 fn fn_maybe_err(tcx: TyCtxt<'_>, sp: Span, abi: Abi) {
525 if let Abi::RustIntrinsic | Abi::PlatformIntrinsic = abi {
526 tcx.sess.span_err(sp, "intrinsic must be in `extern \"rust-intrinsic\" { ... }` block");
530 fn maybe_check_static_with_link_section(tcx: TyCtxt<'_>, id: LocalDefId) {
531 // Only restricted on wasm target for now
532 if !tcx.sess.target.is_like_wasm {
536 // If `#[link_section]` is missing, then nothing to verify
537 let attrs = tcx.codegen_fn_attrs(id);
538 if attrs.link_section.is_none() {
542 // For the wasm32 target statics with `#[link_section]` are placed into custom
543 // sections of the final output file, but this isn't link custom sections of
544 // other executable formats. Namely we can only embed a list of bytes,
545 // nothing with provenance (pointers to anything else). If any provenance
546 // show up, reject it here.
547 // `#[link_section]` may contain arbitrary, or even undefined bytes, but it is
548 // the consumer's responsibility to ensure all bytes that have been read
549 // have defined values.
550 if let Ok(alloc) = tcx.eval_static_initializer(id.to_def_id())
551 && alloc.inner().provenance().len() != 0
553 let msg = "statics with a custom `#[link_section]` must be a \
554 simple list of bytes on the wasm target with no \
555 extra levels of indirection such as references";
556 tcx.sess.span_err(tcx.def_span(id), msg);
560 fn report_forbidden_specialization(
562 impl_item: &hir::ImplItemRef,
565 let mut err = struct_span_err!(
569 "`{}` specializes an item from a parent `impl`, but \
570 that item is not marked `default`",
573 err.span_label(impl_item.span, format!("cannot specialize default item `{}`", impl_item.ident));
575 match tcx.span_of_impl(parent_impl) {
577 err.span_label(span, "parent `impl` is here");
579 "to specialize, `{}` in the parent `impl` must be marked `default`",
584 err.note(&format!("parent implementation is in crate `{cname}`"));
591 fn missing_items_err(
594 missing_items: &[&ty::AssocItem],
595 full_impl_span: Span,
597 let missing_items_msg = missing_items
599 .map(|trait_item| trait_item.name.to_string())
603 let mut err = struct_span_err!(
607 "not all trait items implemented, missing: `{missing_items_msg}`",
609 err.span_label(impl_span, format!("missing `{missing_items_msg}` in implementation"));
611 // `Span` before impl block closing brace.
612 let hi = full_impl_span.hi() - BytePos(1);
613 // Point at the place right before the closing brace of the relevant `impl` to suggest
614 // adding the associated item at the end of its body.
615 let sugg_sp = full_impl_span.with_lo(hi).with_hi(hi);
616 // Obtain the level of indentation ending in `sugg_sp`.
618 tcx.sess.source_map().indentation_before(sugg_sp).unwrap_or_else(|| String::new());
620 for trait_item in missing_items {
621 let snippet = suggestion_signature(trait_item, tcx);
622 let code = format!("{}{}\n{}", padding, snippet, padding);
623 let msg = format!("implement the missing item: `{snippet}`");
624 let appl = Applicability::HasPlaceholders;
625 if let Some(span) = tcx.hir().span_if_local(trait_item.def_id) {
626 err.span_label(span, format!("`{}` from trait", trait_item.name));
627 err.tool_only_span_suggestion(sugg_sp, &msg, code, appl);
629 err.span_suggestion_hidden(sugg_sp, &msg, code, appl);
635 fn missing_items_must_implement_one_of_err(
638 missing_items: &[Ident],
639 annotation_span: Option<Span>,
641 let missing_items_msg =
642 missing_items.iter().map(Ident::to_string).collect::<Vec<_>>().join("`, `");
644 let mut err = struct_span_err!(
648 "not all trait items implemented, missing one of: `{missing_items_msg}`",
650 err.span_label(impl_span, format!("missing one of `{missing_items_msg}` in implementation"));
652 if let Some(annotation_span) = annotation_span {
653 err.span_note(annotation_span, "required because of this annotation");
659 fn default_body_is_unstable(
664 reason: Option<Symbol>,
665 issue: Option<NonZeroU32>,
667 let missing_item_name = &tcx.associated_item(item_did).name;
668 let use_of_unstable_library_feature_note = match reason {
669 Some(r) => format!("use of unstable library feature '{feature}': {r}"),
670 None => format!("use of unstable library feature '{feature}'"),
673 let mut err = struct_span_err!(
677 "not all trait items implemented, missing: `{missing_item_name}`",
679 err.note(format!("default implementation of `{missing_item_name}` is unstable"));
680 err.note(use_of_unstable_library_feature_note);
681 rustc_session::parse::add_feature_diagnostics_for_issue(
683 &tcx.sess.parse_sess,
685 rustc_feature::GateIssue::Library(issue),
690 /// Re-sugar `ty::GenericPredicates` in a way suitable to be used in structured suggestions.
691 fn bounds_from_generic_predicates<'tcx>(
693 predicates: ty::GenericPredicates<'tcx>,
694 ) -> (String, String) {
695 let mut types: FxHashMap<Ty<'tcx>, Vec<DefId>> = FxHashMap::default();
696 let mut projections = vec![];
697 for (predicate, _) in predicates.predicates {
698 debug!("predicate {:?}", predicate);
699 let bound_predicate = predicate.kind();
700 match bound_predicate.skip_binder() {
701 ty::PredicateKind::Trait(trait_predicate) => {
702 let entry = types.entry(trait_predicate.self_ty()).or_default();
703 let def_id = trait_predicate.def_id();
704 if Some(def_id) != tcx.lang_items().sized_trait() {
705 // Type params are `Sized` by default, do not add that restriction to the list
706 // if it is a positive requirement.
707 entry.push(trait_predicate.def_id());
710 ty::PredicateKind::Projection(projection_pred) => {
711 projections.push(bound_predicate.rebind(projection_pred));
716 let generics = if types.is_empty() {
723 .filter_map(|t| match t.kind() {
724 ty::Param(_) => Some(t.to_string()),
725 // Avoid suggesting the following:
726 // fn foo<T, <T as Trait>::Bar>(_: T) where T: Trait, <T as Trait>::Bar: Other {}
733 let mut where_clauses = vec![];
734 for (ty, bounds) in types {
736 .extend(bounds.into_iter().map(|bound| format!("{}: {}", ty, tcx.def_path_str(bound))));
738 for projection in &projections {
739 let p = projection.skip_binder();
740 // FIXME: this is not currently supported syntax, we should be looking at the `types` and
741 // insert the associated types where they correspond, but for now let's be "lazy" and
742 // propose this instead of the following valid resugaring:
743 // `T: Trait, Trait::Assoc = K` → `T: Trait<Assoc = K>`
744 where_clauses.push(format!(
746 tcx.def_path_str(p.projection_ty.item_def_id),
750 let where_clauses = if where_clauses.is_empty() {
753 format!(" where {}", where_clauses.join(", "))
755 (generics, where_clauses)
758 /// Return placeholder code for the given function.
759 fn fn_sig_suggestion<'tcx>(
761 sig: ty::FnSig<'tcx>,
763 predicates: ty::GenericPredicates<'tcx>,
764 assoc: &ty::AssocItem,
771 Some(match ty.kind() {
772 ty::Param(_) if assoc.fn_has_self_parameter && i == 0 => "self".to_string(),
773 ty::Ref(reg, ref_ty, mutability) if i == 0 => {
774 let reg = format!("{reg} ");
775 let reg = match ®[..] {
779 if assoc.fn_has_self_parameter {
780 match ref_ty.kind() {
781 ty::Param(param) if param.name == kw::SelfUpper => {
782 format!("&{}{}self", reg, mutability.prefix_str())
785 _ => format!("self: {ty}"),
792 if assoc.fn_has_self_parameter && i == 0 {
793 format!("self: {ty}")
800 .chain(std::iter::once(if sig.c_variadic { Some("...".to_string()) } else { None }))
802 .collect::<Vec<String>>()
804 let output = sig.output();
805 let output = if !output.is_unit() { format!(" -> {output}") } else { String::new() };
807 let unsafety = sig.unsafety.prefix_str();
808 let (generics, where_clauses) = bounds_from_generic_predicates(tcx, predicates);
810 // FIXME: this is not entirely correct, as the lifetimes from borrowed params will
811 // not be present in the `fn` definition, not will we account for renamed
812 // lifetimes between the `impl` and the `trait`, but this should be good enough to
813 // fill in a significant portion of the missing code, and other subsequent
814 // suggestions can help the user fix the code.
815 format!("{unsafety}fn {ident}{generics}({args}){output}{where_clauses} {{ todo!() }}")
818 /// Return placeholder code for the given associated item.
819 /// Similar to `ty::AssocItem::suggestion`, but appropriate for use as the code snippet of a
820 /// structured suggestion.
821 fn suggestion_signature(assoc: &ty::AssocItem, tcx: TyCtxt<'_>) -> String {
823 ty::AssocKind::Fn => {
824 // We skip the binder here because the binder would deanonymize all
825 // late-bound regions, and we don't want method signatures to show up
826 // `as for<'r> fn(&'r MyType)`. Pretty-printing handles late-bound
827 // regions just fine, showing `fn(&MyType)`.
830 tcx.fn_sig(assoc.def_id).skip_binder(),
832 tcx.predicates_of(assoc.def_id),
836 ty::AssocKind::Type => format!("type {} = Type;", assoc.name),
837 ty::AssocKind::Const => {
838 let ty = tcx.type_of(assoc.def_id);
839 let val = expr::ty_kind_suggestion(ty).unwrap_or("value");
840 format!("const {}: {} = {};", assoc.name, ty, val)
845 /// Emit an error when encountering two or more variants in a transparent enum.
846 fn bad_variant_count<'tcx>(tcx: TyCtxt<'tcx>, adt: ty::AdtDef<'tcx>, sp: Span, did: DefId) {
847 let variant_spans: Vec<_> = adt
850 .map(|variant| tcx.hir().span_if_local(variant.def_id).unwrap())
852 let msg = format!("needs exactly one variant, but has {}", adt.variants().len(),);
853 let mut err = struct_span_err!(tcx.sess, sp, E0731, "transparent enum {msg}");
854 err.span_label(sp, &msg);
855 if let [start @ .., end] = &*variant_spans {
856 for variant_span in start {
857 err.span_label(*variant_span, "");
859 err.span_label(*end, &format!("too many variants in `{}`", tcx.def_path_str(did)));
864 /// Emit an error when encountering two or more non-zero-sized fields in a transparent
866 fn bad_non_zero_sized_fields<'tcx>(
868 adt: ty::AdtDef<'tcx>,
870 field_spans: impl Iterator<Item = Span>,
873 let msg = format!("needs at most one non-zero-sized field, but has {field_count}");
874 let mut err = struct_span_err!(
878 "{}transparent {} {}",
879 if adt.is_enum() { "the variant of a " } else { "" },
883 err.span_label(sp, &msg);
884 for sp in field_spans {
885 err.span_label(sp, "this field is non-zero-sized");
890 fn report_unexpected_variant_res(tcx: TyCtxt<'_>, res: Res, qpath: &hir::QPath<'_>, span: Span) {
895 "expected unit struct, unit variant or constant, found {} `{}`",
897 rustc_hir_pretty::qpath_to_string(qpath),
902 /// Controls whether the arguments are tupled. This is used for the call
905 /// Tupling means that all call-side arguments are packed into a tuple and
906 /// passed as a single parameter. For example, if tupling is enabled, this
909 /// fn f(x: (isize, isize)) {}
911 /// Can be called as:
912 /// ```ignore UNSOLVED (can this be done in user code?)
913 /// # fn f(x: (isize, isize)) {}
918 /// # fn f(x: (isize, isize)) {}
921 #[derive(Clone, Eq, PartialEq)]
922 enum TupleArgumentsFlag {
927 fn typeck_item_bodies(tcx: TyCtxt<'_>, (): ()) {
928 tcx.hir().par_body_owners(|body_owner_def_id| tcx.ensure().typeck(body_owner_def_id));
931 fn fatally_break_rust(sess: &Session) {
932 let handler = sess.diagnostic();
933 handler.span_bug_no_panic(
935 "It looks like you're trying to break rust; would you like some ICE?",
937 handler.note_without_error("the compiler expectedly panicked. this is a feature.");
938 handler.note_without_error(
939 "we would appreciate a joke overview: \
940 https://github.com/rust-lang/rust/issues/43162#issuecomment-320764675",
942 handler.note_without_error(&format!(
943 "rustc {} running on {}",
944 option_env!("CFG_VERSION").unwrap_or("unknown_version"),
945 config::host_triple(),
949 fn potentially_plural_count(count: usize, word: &str) -> String {
950 format!("{} {}{}", count, word, pluralize!(count))
953 fn has_expected_num_generic_args<'tcx>(
955 trait_did: Option<DefId>,
958 trait_did.map_or(true, |trait_did| {
959 let generics = tcx.generics_of(trait_did);
960 generics.count() == expected + if generics.has_self { 1 } else { 0 }
964 /// Suggests calling the constructor of a tuple struct or enum variant
966 /// * `snippet` - The snippet of code that references the constructor
967 /// * `span` - The span of the snippet
968 /// * `params` - The number of parameters the constructor accepts
969 /// * `err` - A mutable diagnostic builder to add the suggestion to
970 fn suggest_call_constructor(span: Span, kind: CtorOf, params: usize, err: &mut Diagnostic) {
971 // Note: tuple-structs don't have named fields, so just use placeholders
972 let args = vec!["_"; params].join(", ");
973 let applicable = if params > 0 {
974 Applicability::HasPlaceholders
976 // When n = 0, it's an empty-tuple struct/enum variant
977 // so we trivially know how to construct it
978 Applicability::MachineApplicable
980 let kind = match kind {
981 CtorOf::Struct => "a struct",
982 CtorOf::Variant => "an enum variant",
984 err.span_label(span, &format!("this is the constructor of {kind}"));
985 err.multipart_suggestion(
986 "call the constructor",
987 vec![(span.shrink_to_lo(), "(".to_string()), (span.shrink_to_hi(), format!(")({args})"))],