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;
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;
131 use std::cell::RefCell;
133 use crate::require_c_abi_if_c_variadic;
134 use crate::util::common::indenter;
136 use self::coercion::DynamicCoerceMany;
137 use self::region::region_scope_tree;
138 pub use self::Expectation::*;
141 macro_rules! type_error_struct {
142 ($session:expr, $span:expr, $typ:expr, $code:ident, $($message:tt)*) => ({
143 let mut err = rustc_errors::struct_span_err!($session, $span, $code, $($message)*);
145 if $typ.references_error() {
146 err.downgrade_to_delayed_bug();
153 /// The type of a local binding, including the revealed type for anon types.
154 #[derive(Copy, Clone, Debug)]
155 pub struct LocalTy<'tcx> {
157 revealed_ty: Ty<'tcx>,
160 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
167 fn maybe_mut_place(m: hir::Mutability) -> Self {
169 hir::Mutability::Mut => Needs::MutPlace,
170 hir::Mutability::Not => Needs::None,
175 #[derive(Copy, Clone)]
176 pub struct UnsafetyState {
178 pub unsafety: hir::Unsafety,
183 pub fn function(unsafety: hir::Unsafety, def: hir::HirId) -> UnsafetyState {
184 UnsafetyState { def, unsafety, from_fn: true }
187 pub fn recurse(self, blk: &hir::Block<'_>) -> UnsafetyState {
188 use hir::BlockCheckMode;
189 match self.unsafety {
190 // If this unsafe, then if the outer function was already marked as
191 // unsafe we shouldn't attribute the unsafe'ness to the block. This
192 // way the block can be warned about instead of ignoring this
193 // extraneous block (functions are never warned about).
194 hir::Unsafety::Unsafe if self.from_fn => self,
197 let (unsafety, def) = match blk.rules {
198 BlockCheckMode::UnsafeBlock(..) => (hir::Unsafety::Unsafe, blk.hir_id),
199 BlockCheckMode::DefaultBlock => (unsafety, self.def),
201 UnsafetyState { def, unsafety, from_fn: false }
207 #[derive(Debug, Copy, Clone)]
213 pub struct BreakableCtxt<'tcx> {
216 // this is `null` for loops where break with a value is illegal,
217 // such as `while`, `for`, and `while let`
218 coerce: Option<DynamicCoerceMany<'tcx>>,
221 pub struct EnclosingBreakables<'tcx> {
222 stack: Vec<BreakableCtxt<'tcx>>,
223 by_id: HirIdMap<usize>,
226 impl<'tcx> EnclosingBreakables<'tcx> {
227 fn find_breakable(&mut self, target_id: hir::HirId) -> &mut BreakableCtxt<'tcx> {
228 self.opt_find_breakable(target_id).unwrap_or_else(|| {
229 bug!("could not find enclosing breakable with id {}", target_id);
233 fn opt_find_breakable(&mut self, target_id: hir::HirId) -> Option<&mut BreakableCtxt<'tcx>> {
234 match self.by_id.get(&target_id) {
235 Some(ix) => Some(&mut self.stack[*ix]),
241 pub fn provide(providers: &mut Providers) {
242 method::provide(providers);
243 wfcheck::provide(providers);
244 *providers = Providers {
248 diagnostic_only_typeck,
252 check_mod_item_types,
258 fn adt_destructor(tcx: TyCtxt<'_>, def_id: DefId) -> Option<ty::Destructor> {
259 tcx.calculate_dtor(def_id, dropck::check_drop_impl)
262 /// If this `DefId` is a "primary tables entry", returns
263 /// `Some((body_id, body_ty, fn_sig))`. Otherwise, returns `None`.
265 /// If this function returns `Some`, then `typeck_results(def_id)` will
266 /// succeed; if it returns `None`, then `typeck_results(def_id)` may or
267 /// may not succeed. In some cases where this function returns `None`
268 /// (notably closures), `typeck_results(def_id)` would wind up
269 /// redirecting to the owning function.
273 ) -> Option<(hir::BodyId, Option<&hir::Ty<'_>>, Option<&hir::FnSig<'_>>)> {
274 match tcx.hir().get(id) {
275 Node::Item(item) => match item.kind {
276 hir::ItemKind::Const(ty, body) | hir::ItemKind::Static(ty, _, body) => {
277 Some((body, Some(ty), None))
279 hir::ItemKind::Fn(ref sig, .., body) => Some((body, None, Some(sig))),
282 Node::TraitItem(item) => match item.kind {
283 hir::TraitItemKind::Const(ty, Some(body)) => Some((body, Some(ty), None)),
284 hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Provided(body)) => {
285 Some((body, None, Some(sig)))
289 Node::ImplItem(item) => match item.kind {
290 hir::ImplItemKind::Const(ty, body) => Some((body, Some(ty), None)),
291 hir::ImplItemKind::Fn(ref sig, body) => Some((body, None, Some(sig))),
294 Node::AnonConst(constant) => Some((constant.body, None, None)),
299 fn has_typeck_results(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
300 // Closures' typeck results come from their outermost function,
301 // as they are part of the same "inference environment".
302 let typeck_root_def_id = tcx.typeck_root_def_id(def_id);
303 if typeck_root_def_id != def_id {
304 return tcx.has_typeck_results(typeck_root_def_id);
307 if let Some(def_id) = def_id.as_local() {
308 let id = tcx.hir().local_def_id_to_hir_id(def_id);
309 primary_body_of(tcx, id).is_some()
315 fn used_trait_imports(tcx: TyCtxt<'_>, def_id: LocalDefId) -> &FxHashSet<LocalDefId> {
316 &*tcx.typeck(def_id).used_trait_imports
319 fn typeck_const_arg<'tcx>(
321 (did, param_did): (LocalDefId, DefId),
322 ) -> &ty::TypeckResults<'tcx> {
323 let fallback = move || tcx.type_of(param_did);
324 typeck_with_fallback(tcx, did, fallback)
327 fn typeck<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &ty::TypeckResults<'tcx> {
328 if let Some(param_did) = tcx.opt_const_param_of(def_id) {
329 tcx.typeck_const_arg((def_id, param_did))
331 let fallback = move || tcx.type_of(def_id.to_def_id());
332 typeck_with_fallback(tcx, def_id, fallback)
336 /// Used only to get `TypeckResults` for type inference during error recovery.
337 /// Currently only used for type inference of `static`s and `const`s to avoid type cycle errors.
338 fn diagnostic_only_typeck<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &ty::TypeckResults<'tcx> {
339 let fallback = move || {
340 let span = tcx.hir().span(tcx.hir().local_def_id_to_hir_id(def_id));
341 tcx.ty_error_with_message(span, "diagnostic only typeck table used")
343 typeck_with_fallback(tcx, def_id, fallback)
346 #[instrument(skip(tcx, 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 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 fcx.closure_analyze(body);
464 assert!(fcx.deferred_call_resolutions.borrow().is_empty());
465 // Before the generator analysis, temporary scopes shall be marked to provide more
466 // precise information on types to be captured.
467 fcx.resolve_rvalue_scopes(def_id.to_def_id());
468 fcx.resolve_generator_interiors(def_id.to_def_id());
470 for (ty, span, code) in fcx.deferred_sized_obligations.borrow_mut().drain(..) {
471 let ty = fcx.normalize_ty(span, ty);
472 fcx.require_type_is_sized(ty, span, code);
475 fcx.select_all_obligations_or_error();
477 if !fcx.infcx.is_tainted_by_errors() {
478 fcx.check_transmutes();
483 fcx.infcx.skip_region_resolution();
485 fcx.resolve_type_vars_in_body(body)
488 // Consistency check our TypeckResults instance can hold all ItemLocalIds
489 // it will need to hold.
490 assert_eq!(typeck_results.hir_owner, id.owner);
495 /// When `check_fn` is invoked on a generator (i.e., a body that
496 /// includes yield), it returns back some information about the yield
498 struct GeneratorTypes<'tcx> {
499 /// Type of generator argument / values returned by `yield`.
502 /// Type of value that is yielded.
505 /// Types that are captured (see `GeneratorInterior` for more).
508 /// Indicates if the generator is movable or static (immovable).
509 movability: hir::Movability,
512 /// Given a `DefId` for an opaque type in return position, find its parent item's return
514 fn get_owner_return_paths<'tcx>(
517 ) -> Option<(LocalDefId, ReturnsVisitor<'tcx>)> {
518 let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
519 let parent_id = tcx.hir().get_parent_item(hir_id);
520 tcx.hir().find_by_def_id(parent_id).and_then(|node| node.body_id()).map(|body_id| {
521 let body = tcx.hir().body(body_id);
522 let mut visitor = ReturnsVisitor::default();
523 visitor.visit_body(body);
528 // Forbid defining intrinsics in Rust code,
529 // as they must always be defined by the compiler.
530 fn fn_maybe_err(tcx: TyCtxt<'_>, sp: Span, abi: Abi) {
531 if let Abi::RustIntrinsic | Abi::PlatformIntrinsic = abi {
532 tcx.sess.span_err(sp, "intrinsic must be in `extern \"rust-intrinsic\" { ... }` block");
536 fn maybe_check_static_with_link_section(tcx: TyCtxt<'_>, id: LocalDefId) {
537 // Only restricted on wasm target for now
538 if !tcx.sess.target.is_like_wasm {
542 // If `#[link_section]` is missing, then nothing to verify
543 let attrs = tcx.codegen_fn_attrs(id);
544 if attrs.link_section.is_none() {
548 // For the wasm32 target statics with `#[link_section]` are placed into custom
549 // sections of the final output file, but this isn't link custom sections of
550 // other executable formats. Namely we can only embed a list of bytes,
551 // nothing with pointers to anything else or relocations. If any relocation
552 // show up, reject them here.
553 // `#[link_section]` may contain arbitrary, or even undefined bytes, but it is
554 // the consumer's responsibility to ensure all bytes that have been read
555 // have defined values.
556 if let Ok(alloc) = tcx.eval_static_initializer(id.to_def_id())
557 && alloc.inner().relocations().len() != 0
559 let msg = "statics with a custom `#[link_section]` must be a \
560 simple list of bytes on the wasm target with no \
561 extra levels of indirection such as references";
562 tcx.sess.span_err(tcx.def_span(id), msg);
566 fn report_forbidden_specialization(
568 impl_item: &hir::ImplItemRef,
571 let mut err = struct_span_err!(
575 "`{}` specializes an item from a parent `impl`, but \
576 that item is not marked `default`",
579 err.span_label(impl_item.span, format!("cannot specialize default item `{}`", impl_item.ident));
581 match tcx.span_of_impl(parent_impl) {
583 err.span_label(span, "parent `impl` is here");
585 "to specialize, `{}` in the parent `impl` must be marked `default`",
590 err.note(&format!("parent implementation is in crate `{cname}`"));
597 fn missing_items_err(
600 missing_items: &[&ty::AssocItem],
601 full_impl_span: Span,
603 let missing_items_msg = missing_items
605 .map(|trait_item| trait_item.name.to_string())
609 let mut err = struct_span_err!(
613 "not all trait items implemented, missing: `{missing_items_msg}`",
615 err.span_label(impl_span, format!("missing `{missing_items_msg}` in implementation"));
617 // `Span` before impl block closing brace.
618 let hi = full_impl_span.hi() - BytePos(1);
619 // Point at the place right before the closing brace of the relevant `impl` to suggest
620 // adding the associated item at the end of its body.
621 let sugg_sp = full_impl_span.with_lo(hi).with_hi(hi);
622 // Obtain the level of indentation ending in `sugg_sp`.
624 tcx.sess.source_map().indentation_before(sugg_sp).unwrap_or_else(|| String::new());
626 for trait_item in missing_items {
627 let snippet = suggestion_signature(trait_item, tcx);
628 let code = format!("{}{}\n{}", padding, snippet, padding);
629 let msg = format!("implement the missing item: `{snippet}`");
630 let appl = Applicability::HasPlaceholders;
631 if let Some(span) = tcx.hir().span_if_local(trait_item.def_id) {
632 err.span_label(span, format!("`{}` from trait", trait_item.name));
633 err.tool_only_span_suggestion(sugg_sp, &msg, code, appl);
635 err.span_suggestion_hidden(sugg_sp, &msg, code, appl);
641 fn missing_items_must_implement_one_of_err(
644 missing_items: &[Ident],
645 annotation_span: Option<Span>,
647 let missing_items_msg =
648 missing_items.iter().map(Ident::to_string).collect::<Vec<_>>().join("`, `");
650 let mut err = struct_span_err!(
654 "not all trait items implemented, missing one of: `{missing_items_msg}`",
656 err.span_label(impl_span, format!("missing one of `{missing_items_msg}` in implementation"));
658 if let Some(annotation_span) = annotation_span {
659 err.span_note(annotation_span, "required because of this annotation");
665 /// Re-sugar `ty::GenericPredicates` in a way suitable to be used in structured suggestions.
666 fn bounds_from_generic_predicates<'tcx>(
668 predicates: ty::GenericPredicates<'tcx>,
669 ) -> (String, String) {
670 let mut types: FxHashMap<Ty<'tcx>, Vec<DefId>> = FxHashMap::default();
671 let mut projections = vec![];
672 for (predicate, _) in predicates.predicates {
673 debug!("predicate {:?}", predicate);
674 let bound_predicate = predicate.kind();
675 match bound_predicate.skip_binder() {
676 ty::PredicateKind::Trait(trait_predicate) => {
677 let entry = types.entry(trait_predicate.self_ty()).or_default();
678 let def_id = trait_predicate.def_id();
679 if Some(def_id) != tcx.lang_items().sized_trait() {
680 // Type params are `Sized` by default, do not add that restriction to the list
681 // if it is a positive requirement.
682 entry.push(trait_predicate.def_id());
685 ty::PredicateKind::Projection(projection_pred) => {
686 projections.push(bound_predicate.rebind(projection_pred));
691 let generics = if types.is_empty() {
698 .filter_map(|t| match t.kind() {
699 ty::Param(_) => Some(t.to_string()),
700 // Avoid suggesting the following:
701 // fn foo<T, <T as Trait>::Bar>(_: T) where T: Trait, <T as Trait>::Bar: Other {}
708 let mut where_clauses = vec![];
709 for (ty, bounds) in types {
711 .extend(bounds.into_iter().map(|bound| format!("{}: {}", ty, tcx.def_path_str(bound))));
713 for projection in &projections {
714 let p = projection.skip_binder();
715 // FIXME: this is not currently supported syntax, we should be looking at the `types` and
716 // insert the associated types where they correspond, but for now let's be "lazy" and
717 // propose this instead of the following valid resugaring:
718 // `T: Trait, Trait::Assoc = K` → `T: Trait<Assoc = K>`
719 where_clauses.push(format!(
721 tcx.def_path_str(p.projection_ty.item_def_id),
725 let where_clauses = if where_clauses.is_empty() {
728 format!(" where {}", where_clauses.join(", "))
730 (generics, where_clauses)
733 /// Return placeholder code for the given function.
734 fn fn_sig_suggestion<'tcx>(
736 sig: ty::FnSig<'tcx>,
738 predicates: ty::GenericPredicates<'tcx>,
739 assoc: &ty::AssocItem,
746 Some(match ty.kind() {
747 ty::Param(_) if assoc.fn_has_self_parameter && i == 0 => "self".to_string(),
748 ty::Ref(reg, ref_ty, mutability) if i == 0 => {
749 let reg = format!("{reg} ");
750 let reg = match ®[..] {
754 if assoc.fn_has_self_parameter {
755 match ref_ty.kind() {
756 ty::Param(param) if param.name == kw::SelfUpper => {
757 format!("&{}{}self", reg, mutability.prefix_str())
760 _ => format!("self: {ty}"),
767 if assoc.fn_has_self_parameter && i == 0 {
768 format!("self: {ty}")
775 .chain(std::iter::once(if sig.c_variadic { Some("...".to_string()) } else { None }))
777 .collect::<Vec<String>>()
779 let output = sig.output();
780 let output = if !output.is_unit() { format!(" -> {output}") } else { String::new() };
782 let unsafety = sig.unsafety.prefix_str();
783 let (generics, where_clauses) = bounds_from_generic_predicates(tcx, predicates);
785 // FIXME: this is not entirely correct, as the lifetimes from borrowed params will
786 // not be present in the `fn` definition, not will we account for renamed
787 // lifetimes between the `impl` and the `trait`, but this should be good enough to
788 // fill in a significant portion of the missing code, and other subsequent
789 // suggestions can help the user fix the code.
790 format!("{unsafety}fn {ident}{generics}({args}){output}{where_clauses} {{ todo!() }}")
793 /// Return placeholder code for the given associated item.
794 /// Similar to `ty::AssocItem::suggestion`, but appropriate for use as the code snippet of a
795 /// structured suggestion.
796 fn suggestion_signature(assoc: &ty::AssocItem, tcx: TyCtxt<'_>) -> String {
798 ty::AssocKind::Fn => {
799 // We skip the binder here because the binder would deanonymize all
800 // late-bound regions, and we don't want method signatures to show up
801 // `as for<'r> fn(&'r MyType)`. Pretty-printing handles late-bound
802 // regions just fine, showing `fn(&MyType)`.
805 tcx.fn_sig(assoc.def_id).skip_binder(),
807 tcx.predicates_of(assoc.def_id),
811 ty::AssocKind::Type => format!("type {} = Type;", assoc.name),
812 ty::AssocKind::Const => {
813 let ty = tcx.type_of(assoc.def_id);
814 let val = expr::ty_kind_suggestion(ty).unwrap_or("value");
815 format!("const {}: {} = {};", assoc.name, ty, val)
820 /// Emit an error when encountering two or more variants in a transparent enum.
821 fn bad_variant_count<'tcx>(tcx: TyCtxt<'tcx>, adt: ty::AdtDef<'tcx>, sp: Span, did: DefId) {
822 let variant_spans: Vec<_> = adt
825 .map(|variant| tcx.hir().span_if_local(variant.def_id).unwrap())
827 let msg = format!("needs exactly one variant, but has {}", adt.variants().len(),);
828 let mut err = struct_span_err!(tcx.sess, sp, E0731, "transparent enum {msg}");
829 err.span_label(sp, &msg);
830 if let [start @ .., end] = &*variant_spans {
831 for variant_span in start {
832 err.span_label(*variant_span, "");
834 err.span_label(*end, &format!("too many variants in `{}`", tcx.def_path_str(did)));
839 /// Emit an error when encountering two or more non-zero-sized fields in a transparent
841 fn bad_non_zero_sized_fields<'tcx>(
843 adt: ty::AdtDef<'tcx>,
845 field_spans: impl Iterator<Item = Span>,
848 let msg = format!("needs at most one non-zero-sized field, but has {field_count}");
849 let mut err = struct_span_err!(
853 "{}transparent {} {}",
854 if adt.is_enum() { "the variant of a " } else { "" },
858 err.span_label(sp, &msg);
859 for sp in field_spans {
860 err.span_label(sp, "this field is non-zero-sized");
865 fn report_unexpected_variant_res(tcx: TyCtxt<'_>, res: Res, qpath: &hir::QPath<'_>, span: Span) {
870 "expected unit struct, unit variant or constant, found {} `{}`",
872 rustc_hir_pretty::qpath_to_string(qpath),
877 /// Controls whether the arguments are tupled. This is used for the call
880 /// Tupling means that all call-side arguments are packed into a tuple and
881 /// passed as a single parameter. For example, if tupling is enabled, this
884 /// fn f(x: (isize, isize)) {}
886 /// Can be called as:
887 /// ```ignore UNSOLVED (can this be done in user code?)
888 /// # fn f(x: (isize, isize)) {}
893 /// # fn f(x: (isize, isize)) {}
896 #[derive(Clone, Eq, PartialEq)]
897 enum TupleArgumentsFlag {
902 fn typeck_item_bodies(tcx: TyCtxt<'_>, (): ()) {
903 tcx.hir().par_body_owners(|body_owner_def_id| tcx.ensure().typeck(body_owner_def_id));
906 fn fatally_break_rust(sess: &Session) {
907 let handler = sess.diagnostic();
908 handler.span_bug_no_panic(
910 "It looks like you're trying to break rust; would you like some ICE?",
912 handler.note_without_error("the compiler expectedly panicked. this is a feature.");
913 handler.note_without_error(
914 "we would appreciate a joke overview: \
915 https://github.com/rust-lang/rust/issues/43162#issuecomment-320764675",
917 handler.note_without_error(&format!(
918 "rustc {} running on {}",
919 option_env!("CFG_VERSION").unwrap_or("unknown_version"),
920 config::host_triple(),
924 fn potentially_plural_count(count: usize, word: &str) -> String {
925 format!("{} {}{}", count, word, pluralize!(count))
928 fn has_expected_num_generic_args<'tcx>(
930 trait_did: Option<DefId>,
933 trait_did.map_or(true, |trait_did| {
934 let generics = tcx.generics_of(trait_did);
935 generics.count() == expected + if generics.has_self { 1 } else { 0 }
939 /// Suggests calling the constructor of a tuple struct or enum variant
941 /// * `snippet` - The snippet of code that references the constructor
942 /// * `span` - The span of the snippet
943 /// * `params` - The number of parameters the constructor accepts
944 /// * `err` - A mutable diagnostic builder to add the suggestion to
945 fn suggest_call_constructor<G: EmissionGuarantee>(
949 err: &mut DiagnosticBuilder<'_, G>,
951 // Note: tuple-structs don't have named fields, so just use placeholders
952 let args = vec!["_"; params].join(", ");
953 let applicable = if params > 0 {
954 Applicability::HasPlaceholders
956 // When n = 0, it's an empty-tuple struct/enum variant
957 // so we trivially know how to construct it
958 Applicability::MachineApplicable
960 let kind = match kind {
961 CtorOf::Struct => "a struct",
962 CtorOf::Variant => "an enum variant",
964 err.span_label(span, &format!("this is the constructor of {kind}"));
965 err.multipart_suggestion(
966 "call the constructor",
967 vec![(span.shrink_to_lo(), "(".to_string()), (span.shrink_to_hi(), format!(")({args})"))],