5 Within the check phase of type check, we check each item one at a time
6 (bodies of function expressions are checked as part of the containing
7 function). Inference is used to supply types wherever they are unknown.
9 By far the most complex case is checking the body of a function. This
10 can be broken down into several distinct phases:
12 - gather: creates type variables to represent the type of each local
13 variable and pattern binding.
15 - main: the main pass does the lion's share of the work: it
16 determines the types of all expressions, resolves
17 methods, checks for most invalid conditions, and so forth. In
18 some cases, where a type is unknown, it may create a type or region
19 variable and use that as the type of an expression.
21 In the process of checking, various constraints will be placed on
22 these type variables through the subtyping relationships requested
23 through the `demand` module. The `infer` module is in charge
24 of resolving those constraints.
26 - regionck: after main is complete, the regionck pass goes over all
27 types looking for regions and making sure that they did not escape
28 into places they are not in scope. This may also influence the
29 final assignments of the various region variables if there is some
32 - writeback: writes the final types within a function body, replacing
33 type variables with their final inferred types. These final types
34 are written into the `tcx.node_types` table, which should *never* contain
35 any reference to a type variable.
39 While type checking a function, the intermediate types for the
40 expressions, blocks, and so forth contained within the function are
41 stored in `fcx.node_types` and `fcx.node_substs`. These types
42 may contain unresolved type variables. After type checking is
43 complete, the functions in the writeback module are used to take the
44 types from this table, resolve them, and then write them into their
45 permanent home in the type context `tcx`.
47 This means that during inferencing you should use `fcx.write_ty()`
48 and `fcx.expr_ty()` / `fcx.node_ty()` to write/obtain the types of
49 nodes within the function.
51 The types of top-level items, which never contain unbound type
52 variables, are stored directly into the `tcx` typeck_results.
54 N.B., a type variable is not the same thing as a type parameter. A
55 type variable is an instance of a type parameter. That is,
56 given a generic function `fn foo<T>(t: T)`, while checking the
57 function `foo`, the type `ty_param(0)` refers to the type `T`, which
58 is treated in abstract. However, when `foo()` is called, `T` will be
59 substituted for a fresh type variable `N`. This variable will
60 eventually be resolved to some concrete type (which might itself be
81 mod generator_interior;
94 check_abi, check_fn, check_impl_item_well_formed, check_item_well_formed, check_mod_item_types,
95 check_trait_item_well_formed,
97 pub use check::{check_item_type, check_wf_new};
98 pub use diverges::Diverges;
99 pub use expectation::Expectation;
101 use hir::def::CtorOf;
102 pub use inherited::{Inherited, InheritedBuilder};
104 use crate::astconv::AstConv;
105 use crate::check::gather_locals::GatherLocalsVisitor;
106 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
108 pluralize, struct_span_err, Applicability, DiagnosticBuilder, EmissionGuarantee, MultiSpan,
110 use rustc_hir as hir;
111 use rustc_hir::def::Res;
112 use rustc_hir::def_id::{DefId, LocalDefId};
113 use rustc_hir::intravisit::Visitor;
114 use rustc_hir::{HirIdMap, ImplicitSelfKind, Node};
115 use rustc_index::bit_set::BitSet;
116 use rustc_index::vec::Idx;
117 use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
118 use rustc_middle::ty::query::Providers;
119 use rustc_middle::ty::subst::{InternalSubsts, Subst, SubstsRef};
120 use rustc_middle::ty::{self, Ty, TyCtxt, UserType};
121 use rustc_session::config;
122 use rustc_session::parse::feature_err;
123 use rustc_session::Session;
124 use rustc_span::source_map::DUMMY_SP;
125 use rustc_span::symbol::{kw, Ident};
126 use rustc_span::{self, BytePos, Span};
127 use rustc_target::abi::VariantIdx;
128 use rustc_target::spec::abi::Abi;
129 use rustc_trait_selection::traits;
130 use rustc_trait_selection::traits::error_reporting::recursive_type_with_infinite_size_error;
131 use rustc_trait_selection::traits::error_reporting::suggestions::ReturnsVisitor;
133 use std::cell::{Ref, RefCell, RefMut};
135 use crate::require_c_abi_if_c_variadic;
136 use crate::util::common::indenter;
138 use self::coercion::DynamicCoerceMany;
139 pub use self::Expectation::*;
142 macro_rules! type_error_struct {
143 ($session:expr, $span:expr, $typ:expr, $code:ident, $($message:tt)*) => ({
144 let mut err = rustc_errors::struct_span_err!($session, $span, $code, $($message)*);
146 if $typ.references_error() {
147 err.downgrade_to_delayed_bug();
154 /// The type of a local binding, including the revealed type for anon types.
155 #[derive(Copy, Clone, Debug)]
156 pub struct LocalTy<'tcx> {
158 revealed_ty: Ty<'tcx>,
161 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
168 fn maybe_mut_place(m: hir::Mutability) -> Self {
170 hir::Mutability::Mut => Needs::MutPlace,
171 hir::Mutability::Not => Needs::None,
176 #[derive(Copy, Clone)]
177 pub struct UnsafetyState {
179 pub unsafety: hir::Unsafety,
184 pub fn function(unsafety: hir::Unsafety, def: hir::HirId) -> UnsafetyState {
185 UnsafetyState { def, unsafety, from_fn: true }
188 pub fn recurse(self, blk: &hir::Block<'_>) -> UnsafetyState {
189 use hir::BlockCheckMode;
190 match self.unsafety {
191 // If this unsafe, then if the outer function was already marked as
192 // unsafe we shouldn't attribute the unsafe'ness to the block. This
193 // way the block can be warned about instead of ignoring this
194 // extraneous block (functions are never warned about).
195 hir::Unsafety::Unsafe if self.from_fn => self,
198 let (unsafety, def) = match blk.rules {
199 BlockCheckMode::UnsafeBlock(..) => (hir::Unsafety::Unsafe, blk.hir_id),
200 BlockCheckMode::DefaultBlock => (unsafety, self.def),
202 UnsafetyState { def, unsafety, from_fn: false }
208 #[derive(Debug, Copy, Clone)]
214 pub struct BreakableCtxt<'tcx> {
217 // this is `null` for loops where break with a value is illegal,
218 // such as `while`, `for`, and `while let`
219 coerce: Option<DynamicCoerceMany<'tcx>>,
222 pub struct EnclosingBreakables<'tcx> {
223 stack: Vec<BreakableCtxt<'tcx>>,
224 by_id: HirIdMap<usize>,
227 impl<'tcx> EnclosingBreakables<'tcx> {
228 fn find_breakable(&mut self, target_id: hir::HirId) -> &mut BreakableCtxt<'tcx> {
229 self.opt_find_breakable(target_id).unwrap_or_else(|| {
230 bug!("could not find enclosing breakable with id {}", target_id);
234 fn opt_find_breakable(&mut self, target_id: hir::HirId) -> Option<&mut BreakableCtxt<'tcx>> {
235 match self.by_id.get(&target_id) {
236 Some(ix) => Some(&mut self.stack[*ix]),
242 pub fn provide(providers: &mut Providers) {
243 method::provide(providers);
244 *providers = Providers {
248 diagnostic_only_typeck,
252 check_item_well_formed,
253 check_trait_item_well_formed,
254 check_impl_item_well_formed,
255 check_mod_item_types,
260 fn adt_destructor(tcx: TyCtxt<'_>, def_id: DefId) -> Option<ty::Destructor> {
261 tcx.calculate_dtor(def_id, dropck::check_drop_impl)
264 /// If this `DefId` is a "primary tables entry", returns
265 /// `Some((body_id, body_ty, fn_sig))`. Otherwise, returns `None`.
267 /// If this function returns `Some`, then `typeck_results(def_id)` will
268 /// succeed; if it returns `None`, then `typeck_results(def_id)` may or
269 /// may not succeed. In some cases where this function returns `None`
270 /// (notably closures), `typeck_results(def_id)` would wind up
271 /// redirecting to the owning function.
275 ) -> Option<(hir::BodyId, Option<&hir::Ty<'_>>, Option<&hir::FnSig<'_>>)> {
276 match tcx.hir().get(id) {
277 Node::Item(item) => match item.kind {
278 hir::ItemKind::Const(ty, body) | hir::ItemKind::Static(ty, _, body) => {
279 Some((body, Some(ty), None))
281 hir::ItemKind::Fn(ref sig, .., body) => Some((body, None, Some(sig))),
284 Node::TraitItem(item) => match item.kind {
285 hir::TraitItemKind::Const(ty, Some(body)) => Some((body, Some(ty), None)),
286 hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Provided(body)) => {
287 Some((body, None, Some(sig)))
291 Node::ImplItem(item) => match item.kind {
292 hir::ImplItemKind::Const(ty, body) => Some((body, Some(ty), None)),
293 hir::ImplItemKind::Fn(ref sig, body) => Some((body, None, Some(sig))),
296 Node::AnonConst(constant) => Some((constant.body, None, None)),
301 fn has_typeck_results(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
302 // Closures' typeck results come from their outermost function,
303 // as they are part of the same "inference environment".
304 let typeck_root_def_id = tcx.typeck_root_def_id(def_id);
305 if typeck_root_def_id != def_id {
306 return tcx.has_typeck_results(typeck_root_def_id);
309 if let Some(def_id) = def_id.as_local() {
310 let id = tcx.hir().local_def_id_to_hir_id(def_id);
311 primary_body_of(tcx, id).is_some()
317 fn used_trait_imports(tcx: TyCtxt<'_>, def_id: LocalDefId) -> &FxHashSet<LocalDefId> {
318 &*tcx.typeck(def_id).used_trait_imports
321 fn typeck_const_arg<'tcx>(
323 (did, param_did): (LocalDefId, DefId),
324 ) -> &ty::TypeckResults<'tcx> {
325 let fallback = move || tcx.type_of(param_did);
326 typeck_with_fallback(tcx, did, fallback)
329 fn typeck<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &ty::TypeckResults<'tcx> {
330 if let Some(param_did) = tcx.opt_const_param_of(def_id) {
331 tcx.typeck_const_arg((def_id, param_did))
333 let fallback = move || tcx.type_of(def_id.to_def_id());
334 typeck_with_fallback(tcx, def_id, fallback)
338 /// Used only to get `TypeckResults` for type inference during error recovery.
339 /// Currently only used for type inference of `static`s and `const`s to avoid type cycle errors.
340 fn diagnostic_only_typeck<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &ty::TypeckResults<'tcx> {
341 let fallback = move || {
342 let span = tcx.hir().span(tcx.hir().local_def_id_to_hir_id(def_id));
343 tcx.ty_error_with_message(span, "diagnostic only typeck table used")
345 typeck_with_fallback(tcx, def_id, fallback)
348 #[instrument(skip(tcx, fallback))]
349 fn typeck_with_fallback<'tcx>(
352 fallback: impl Fn() -> Ty<'tcx> + 'tcx,
353 ) -> &'tcx ty::TypeckResults<'tcx> {
354 // Closures' typeck results come from their outermost function,
355 // as they are part of the same "inference environment".
356 let typeck_root_def_id = tcx.typeck_root_def_id(def_id.to_def_id()).expect_local();
357 if typeck_root_def_id != def_id {
358 return tcx.typeck(typeck_root_def_id);
361 let id = tcx.hir().local_def_id_to_hir_id(def_id);
362 let span = tcx.hir().span(id);
364 // Figure out what primary body this item has.
365 let (body_id, body_ty, fn_sig) = primary_body_of(tcx, id).unwrap_or_else(|| {
366 span_bug!(span, "can't type-check body of {:?}", def_id);
368 let body = tcx.hir().body(body_id);
370 let typeck_results = Inherited::build(tcx, def_id).enter(|inh| {
371 let param_env = tcx.param_env(def_id);
372 let (fcx, wf_tys) = if let Some(hir::FnSig { header, decl, .. }) = fn_sig {
373 let fn_sig = if crate::collect::get_infer_ret_ty(&decl.output).is_some() {
374 let fcx = FnCtxt::new(&inh, param_env, body.value.hir_id);
375 <dyn AstConv<'_>>::ty_of_fn(&fcx, id, header.unsafety, header.abi, decl, None, None)
380 check_abi(tcx, id, span, fn_sig.abi());
382 // When normalizing the function signature, we assume all types are
383 // well-formed. So, we don't need to worry about the obligations
384 // from normalization. We could just discard these, but to align with
385 // compare_method and elsewhere, we just add implied bounds for
387 let mut wf_tys = FxHashSet::default();
388 // Compute the fty from point of view of inside the fn.
389 let fn_sig = tcx.liberate_late_bound_regions(def_id.to_def_id(), fn_sig);
390 let fn_sig = inh.normalize_associated_types_in(
396 wf_tys.extend(fn_sig.inputs_and_output.iter());
398 let fcx = check_fn(&inh, param_env, fn_sig, decl, id, body, None, true).0;
401 let fcx = FnCtxt::new(&inh, param_env, body.value.hir_id);
402 let expected_type = body_ty
403 .and_then(|ty| match ty.kind {
404 hir::TyKind::Infer => Some(<dyn AstConv<'_>>::ast_ty_to_ty(&fcx, ty)),
407 .unwrap_or_else(|| match tcx.hir().get(id) {
408 Node::AnonConst(_) => match tcx.hir().get(tcx.hir().get_parent_node(id)) {
409 Node::Expr(&hir::Expr {
410 kind: hir::ExprKind::ConstBlock(ref anon_const),
412 }) if anon_const.hir_id == id => fcx.next_ty_var(TypeVariableOrigin {
413 kind: TypeVariableOriginKind::TypeInference,
417 kind: hir::TyKind::Typeof(ref anon_const), ..
418 }) if anon_const.hir_id == id => fcx.next_ty_var(TypeVariableOrigin {
419 kind: TypeVariableOriginKind::TypeInference,
422 Node::Expr(&hir::Expr { kind: hir::ExprKind::InlineAsm(asm), .. })
423 | Node::Item(&hir::Item { kind: hir::ItemKind::GlobalAsm(asm), .. }) => {
427 .filter_map(|(op, _op_sp)| match op {
428 hir::InlineAsmOperand::Const { anon_const }
429 if anon_const.hir_id == id =>
431 // Inline assembly constants must be integers.
432 Some(fcx.next_int_var())
434 hir::InlineAsmOperand::SymFn { anon_const }
435 if anon_const.hir_id == id =>
437 Some(fcx.next_ty_var(TypeVariableOrigin {
438 kind: TypeVariableOriginKind::MiscVariable,
445 operand_ty.unwrap_or_else(fallback)
452 let expected_type = fcx.normalize_associated_types_in(body.value.span, expected_type);
453 fcx.require_type_is_sized(expected_type, body.value.span, traits::ConstSized);
455 // Gather locals in statics (because of block expressions).
456 GatherLocalsVisitor::new(&fcx).visit_body(body);
458 fcx.check_expr_coercable_to_type(&body.value, expected_type, None);
460 fcx.write_ty(id, expected_type);
462 (fcx, FxHashSet::default())
465 let fallback_has_occurred = fcx.type_inference_fallback();
467 // Even though coercion casts provide type hints, we check casts after fallback for
468 // backwards compatibility. This makes fallback a stronger type hint than a cast coercion.
470 fcx.select_obligations_where_possible(fallback_has_occurred, |_| {});
472 // Closure and generator analysis may run after fallback
473 // because they don't constrain other type variables.
474 fcx.closure_analyze(body);
475 assert!(fcx.deferred_call_resolutions.borrow().is_empty());
476 fcx.resolve_generator_interiors(def_id.to_def_id());
478 for (ty, span, code) in fcx.deferred_sized_obligations.borrow_mut().drain(..) {
479 let ty = fcx.normalize_ty(span, ty);
480 fcx.require_type_is_sized(ty, span, code);
483 fcx.select_all_obligations_or_error();
485 if fn_sig.is_some() {
486 fcx.regionck_fn(id, body, span, wf_tys);
488 fcx.regionck_expr(body);
491 fcx.resolve_type_vars_in_body(body)
494 // Consistency check our TypeckResults instance can hold all ItemLocalIds
495 // it will need to hold.
496 assert_eq!(typeck_results.hir_owner, id.owner);
501 /// When `check_fn` is invoked on a generator (i.e., a body that
502 /// includes yield), it returns back some information about the yield
504 struct GeneratorTypes<'tcx> {
505 /// Type of generator argument / values returned by `yield`.
508 /// Type of value that is yielded.
511 /// Types that are captured (see `GeneratorInterior` for more).
514 /// Indicates if the generator is movable or static (immovable).
515 movability: hir::Movability,
518 /// Given a `DefId` for an opaque type in return position, find its parent item's return
520 fn get_owner_return_paths<'tcx>(
523 ) -> Option<(LocalDefId, ReturnsVisitor<'tcx>)> {
524 let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
525 let parent_id = tcx.hir().get_parent_item(hir_id);
526 tcx.hir().find_by_def_id(parent_id).and_then(|node| node.body_id()).map(|body_id| {
527 let body = tcx.hir().body(body_id);
528 let mut visitor = ReturnsVisitor::default();
529 visitor.visit_body(body);
534 // Forbid defining intrinsics in Rust code,
535 // as they must always be defined by the compiler.
536 fn fn_maybe_err(tcx: TyCtxt<'_>, sp: Span, abi: Abi) {
537 if let Abi::RustIntrinsic | Abi::PlatformIntrinsic = abi {
538 tcx.sess.span_err(sp, "intrinsic must be in `extern \"rust-intrinsic\" { ... }` block");
542 fn maybe_check_static_with_link_section(tcx: TyCtxt<'_>, id: LocalDefId, span: Span) {
543 // Only restricted on wasm target for now
544 if !tcx.sess.target.is_like_wasm {
548 // If `#[link_section]` is missing, then nothing to verify
549 let attrs = tcx.codegen_fn_attrs(id);
550 if attrs.link_section.is_none() {
554 // For the wasm32 target statics with `#[link_section]` are placed into custom
555 // sections of the final output file, but this isn't link custom sections of
556 // other executable formats. Namely we can only embed a list of bytes,
557 // nothing with pointers to anything else or relocations. If any relocation
558 // show up, reject them here.
559 // `#[link_section]` may contain arbitrary, or even undefined bytes, but it is
560 // the consumer's responsibility to ensure all bytes that have been read
561 // have defined values.
562 if let Ok(alloc) = tcx.eval_static_initializer(id.to_def_id())
563 && alloc.inner().relocations().len() != 0
565 let msg = "statics with a custom `#[link_section]` must be a \
566 simple list of bytes on the wasm target with no \
567 extra levels of indirection such as references";
568 tcx.sess.span_err(span, msg);
572 fn report_forbidden_specialization(
574 impl_item: &hir::ImplItemRef,
577 let mut err = struct_span_err!(
581 "`{}` specializes an item from a parent `impl`, but \
582 that item is not marked `default`",
585 err.span_label(impl_item.span, format!("cannot specialize default item `{}`", impl_item.ident));
587 match tcx.span_of_impl(parent_impl) {
589 err.span_label(span, "parent `impl` is here");
591 "to specialize, `{}` in the parent `impl` must be marked `default`",
596 err.note(&format!("parent implementation is in crate `{cname}`"));
603 fn missing_items_err(
606 missing_items: &[&ty::AssocItem],
607 full_impl_span: Span,
609 let missing_items_msg = missing_items
611 .map(|trait_item| trait_item.name.to_string())
615 let mut err = struct_span_err!(
619 "not all trait items implemented, missing: `{missing_items_msg}`",
621 err.span_label(impl_span, format!("missing `{missing_items_msg}` in implementation"));
623 // `Span` before impl block closing brace.
624 let hi = full_impl_span.hi() - BytePos(1);
625 // Point at the place right before the closing brace of the relevant `impl` to suggest
626 // adding the associated item at the end of its body.
627 let sugg_sp = full_impl_span.with_lo(hi).with_hi(hi);
628 // Obtain the level of indentation ending in `sugg_sp`.
629 let indentation = tcx.sess.source_map().span_to_margin(sugg_sp).unwrap_or(0);
630 // Make the whitespace that will make the suggestion have the right indentation.
631 let padding: String = " ".repeat(indentation);
633 for trait_item in missing_items {
634 let snippet = suggestion_signature(trait_item, tcx);
635 let code = format!("{}{}\n{}", padding, snippet, padding);
636 let msg = format!("implement the missing item: `{snippet}`");
637 let appl = Applicability::HasPlaceholders;
638 if let Some(span) = tcx.hir().span_if_local(trait_item.def_id) {
639 err.span_label(span, format!("`{}` from trait", trait_item.name));
640 err.tool_only_span_suggestion(sugg_sp, &msg, code, appl);
642 err.span_suggestion_hidden(sugg_sp, &msg, code, appl);
648 fn missing_items_must_implement_one_of_err(
651 missing_items: &[Ident],
652 annotation_span: Option<Span>,
654 let missing_items_msg =
655 missing_items.iter().map(Ident::to_string).collect::<Vec<_>>().join("`, `");
657 let mut err = struct_span_err!(
661 "not all trait items implemented, missing one of: `{missing_items_msg}`",
663 err.span_label(impl_span, format!("missing one of `{missing_items_msg}` in implementation"));
665 if let Some(annotation_span) = annotation_span {
666 err.span_note(annotation_span, "required because of this annotation");
672 /// Re-sugar `ty::GenericPredicates` in a way suitable to be used in structured suggestions.
673 fn bounds_from_generic_predicates<'tcx>(
675 predicates: ty::GenericPredicates<'tcx>,
676 ) -> (String, String) {
677 let mut types: FxHashMap<Ty<'tcx>, Vec<DefId>> = FxHashMap::default();
678 let mut projections = vec![];
679 for (predicate, _) in predicates.predicates {
680 debug!("predicate {:?}", predicate);
681 let bound_predicate = predicate.kind();
682 match bound_predicate.skip_binder() {
683 ty::PredicateKind::Trait(trait_predicate) => {
684 let entry = types.entry(trait_predicate.self_ty()).or_default();
685 let def_id = trait_predicate.def_id();
686 if Some(def_id) != tcx.lang_items().sized_trait() {
687 // Type params are `Sized` by default, do not add that restriction to the list
688 // if it is a positive requirement.
689 entry.push(trait_predicate.def_id());
692 ty::PredicateKind::Projection(projection_pred) => {
693 projections.push(bound_predicate.rebind(projection_pred));
698 let generics = if types.is_empty() {
705 .filter_map(|t| match t.kind() {
706 ty::Param(_) => Some(t.to_string()),
707 // Avoid suggesting the following:
708 // fn foo<T, <T as Trait>::Bar>(_: T) where T: Trait, <T as Trait>::Bar: Other {}
715 let mut where_clauses = vec![];
716 for (ty, bounds) in types {
718 .extend(bounds.into_iter().map(|bound| format!("{}: {}", ty, tcx.def_path_str(bound))));
720 for projection in &projections {
721 let p = projection.skip_binder();
722 // FIXME: this is not currently supported syntax, we should be looking at the `types` and
723 // insert the associated types where they correspond, but for now let's be "lazy" and
724 // propose this instead of the following valid resugaring:
725 // `T: Trait, Trait::Assoc = K` → `T: Trait<Assoc = K>`
726 where_clauses.push(format!(
728 tcx.def_path_str(p.projection_ty.item_def_id),
732 let where_clauses = if where_clauses.is_empty() {
735 format!(" where {}", where_clauses.join(", "))
737 (generics, where_clauses)
740 /// Return placeholder code for the given function.
741 fn fn_sig_suggestion<'tcx>(
743 sig: ty::FnSig<'tcx>,
745 predicates: ty::GenericPredicates<'tcx>,
746 assoc: &ty::AssocItem,
753 Some(match ty.kind() {
754 ty::Param(_) if assoc.fn_has_self_parameter && i == 0 => "self".to_string(),
755 ty::Ref(reg, ref_ty, mutability) if i == 0 => {
756 let reg = format!("{reg} ");
757 let reg = match ®[..] {
761 if assoc.fn_has_self_parameter {
762 match ref_ty.kind() {
763 ty::Param(param) if param.name == kw::SelfUpper => {
764 format!("&{}{}self", reg, mutability.prefix_str())
767 _ => format!("self: {ty}"),
774 if assoc.fn_has_self_parameter && i == 0 {
775 format!("self: {ty}")
782 .chain(std::iter::once(if sig.c_variadic { Some("...".to_string()) } else { None }))
784 .collect::<Vec<String>>()
786 let output = sig.output();
787 let output = if !output.is_unit() { format!(" -> {output}") } else { String::new() };
789 let unsafety = sig.unsafety.prefix_str();
790 let (generics, where_clauses) = bounds_from_generic_predicates(tcx, predicates);
792 // FIXME: this is not entirely correct, as the lifetimes from borrowed params will
793 // not be present in the `fn` definition, not will we account for renamed
794 // lifetimes between the `impl` and the `trait`, but this should be good enough to
795 // fill in a significant portion of the missing code, and other subsequent
796 // suggestions can help the user fix the code.
797 format!("{unsafety}fn {ident}{generics}({args}){output}{where_clauses} {{ todo!() }}")
800 /// Return placeholder code for the given associated item.
801 /// Similar to `ty::AssocItem::suggestion`, but appropriate for use as the code snippet of a
802 /// structured suggestion.
803 fn suggestion_signature(assoc: &ty::AssocItem, tcx: TyCtxt<'_>) -> String {
805 ty::AssocKind::Fn => {
806 // We skip the binder here because the binder would deanonymize all
807 // late-bound regions, and we don't want method signatures to show up
808 // `as for<'r> fn(&'r MyType)`. Pretty-printing handles late-bound
809 // regions just fine, showing `fn(&MyType)`.
812 tcx.fn_sig(assoc.def_id).skip_binder(),
814 tcx.predicates_of(assoc.def_id),
818 ty::AssocKind::Type => format!("type {} = Type;", assoc.name),
819 ty::AssocKind::Const => {
820 let ty = tcx.type_of(assoc.def_id);
821 let val = expr::ty_kind_suggestion(ty).unwrap_or("value");
822 format!("const {}: {} = {};", assoc.name, ty, val)
827 /// Emit an error when encountering two or more variants in a transparent enum.
828 fn bad_variant_count<'tcx>(tcx: TyCtxt<'tcx>, adt: ty::AdtDef<'tcx>, sp: Span, did: DefId) {
829 let variant_spans: Vec<_> = adt
832 .map(|variant| tcx.hir().span_if_local(variant.def_id).unwrap())
834 let msg = format!("needs exactly one variant, but has {}", adt.variants().len(),);
835 let mut err = struct_span_err!(tcx.sess, sp, E0731, "transparent enum {msg}");
836 err.span_label(sp, &msg);
837 if let [start @ .., end] = &*variant_spans {
838 for variant_span in start {
839 err.span_label(*variant_span, "");
841 err.span_label(*end, &format!("too many variants in `{}`", tcx.def_path_str(did)));
846 /// Emit an error when encountering two or more non-zero-sized fields in a transparent
848 fn bad_non_zero_sized_fields<'tcx>(
850 adt: ty::AdtDef<'tcx>,
852 field_spans: impl Iterator<Item = Span>,
855 let msg = format!("needs at most one non-zero-sized field, but has {field_count}");
856 let mut err = struct_span_err!(
860 "{}transparent {} {}",
861 if adt.is_enum() { "the variant of a " } else { "" },
865 err.span_label(sp, &msg);
866 for sp in field_spans {
867 err.span_label(sp, "this field is non-zero-sized");
872 fn report_unexpected_variant_res(tcx: TyCtxt<'_>, res: Res, span: Span) {
877 "expected unit struct, unit variant or constant, found {}{}",
881 .span_to_snippet(span)
882 .map_or_else(|_| String::new(), |s| format!(" `{s}`",)),
887 /// Controls whether the arguments are tupled. This is used for the call
890 /// Tupling means that all call-side arguments are packed into a tuple and
891 /// passed as a single parameter. For example, if tupling is enabled, this
894 /// fn f(x: (isize, isize)) {}
896 /// Can be called as:
897 /// ```ignore UNSOLVED (can this be done in user code?)
898 /// # fn f(x: (isize, isize)) {}
903 /// # fn f(x: (isize, isize)) {}
906 #[derive(Clone, Eq, PartialEq)]
907 enum TupleArgumentsFlag {
912 /// A wrapper for `InferCtxt`'s `in_progress_typeck_results` field.
913 #[derive(Copy, Clone)]
914 struct MaybeInProgressTables<'a, 'tcx> {
915 maybe_typeck_results: Option<&'a RefCell<ty::TypeckResults<'tcx>>>,
918 impl<'a, 'tcx> MaybeInProgressTables<'a, 'tcx> {
919 fn borrow(self) -> Ref<'a, ty::TypeckResults<'tcx>> {
920 match self.maybe_typeck_results {
921 Some(typeck_results) => typeck_results.borrow(),
923 "MaybeInProgressTables: inh/fcx.typeck_results.borrow() with no typeck results"
928 fn borrow_mut(self) -> RefMut<'a, ty::TypeckResults<'tcx>> {
929 match self.maybe_typeck_results {
930 Some(typeck_results) => typeck_results.borrow_mut(),
932 "MaybeInProgressTables: inh/fcx.typeck_results.borrow_mut() with no typeck results"
938 fn typeck_item_bodies(tcx: TyCtxt<'_>, (): ()) {
939 tcx.hir().par_body_owners(|body_owner_def_id| tcx.ensure().typeck(body_owner_def_id));
942 fn fatally_break_rust(sess: &Session) {
943 let handler = sess.diagnostic();
944 handler.span_bug_no_panic(
946 "It looks like you're trying to break rust; would you like some ICE?",
948 handler.note_without_error("the compiler expectedly panicked. this is a feature.");
949 handler.note_without_error(
950 "we would appreciate a joke overview: \
951 https://github.com/rust-lang/rust/issues/43162#issuecomment-320764675",
953 handler.note_without_error(&format!(
954 "rustc {} running on {}",
955 option_env!("CFG_VERSION").unwrap_or("unknown_version"),
956 config::host_triple(),
960 fn potentially_plural_count(count: usize, word: &str) -> String {
961 format!("{} {}{}", count, word, pluralize!(count))
964 fn has_expected_num_generic_args<'tcx>(
966 trait_did: Option<DefId>,
969 trait_did.map_or(true, |trait_did| {
970 let generics = tcx.generics_of(trait_did);
971 generics.count() == expected + if generics.has_self { 1 } else { 0 }
975 /// Suggests calling the constructor of a tuple struct or enum variant
977 /// * `snippet` - The snippet of code that references the constructor
978 /// * `span` - The span of the snippet
979 /// * `params` - The number of parameters the constructor accepts
980 /// * `err` - A mutable diagnostic builder to add the suggestion to
981 fn suggest_call_constructor<G: EmissionGuarantee>(
985 err: &mut DiagnosticBuilder<'_, G>,
987 // Note: tuple-structs don't have named fields, so just use placeholders
988 let args = vec!["_"; params].join(", ");
989 let applicable = if params > 0 {
990 Applicability::HasPlaceholders
992 // When n = 0, it's an empty-tuple struct/enum variant
993 // so we trivially know how to construct it
994 Applicability::MachineApplicable
996 let kind = match kind {
997 CtorOf::Struct => "a struct",
998 CtorOf::Variant => "an enum variant",
1000 err.span_label(span, &format!("this is the constructor of {kind}"));
1001 err.multipart_suggestion(
1002 "call the constructor",
1003 vec![(span.shrink_to_lo(), "(".to_string()), (span.shrink_to_hi(), format!(")({args})"))],