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 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};
106 use rustc_errors::{pluralize, struct_span_err, Applicability, 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::itemlikevisit::ItemLikeVisitor;
112 use rustc_hir::{HirIdMap, ImplicitSelfKind, Node};
113 use rustc_index::bit_set::BitSet;
114 use rustc_index::vec::Idx;
115 use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
116 use rustc_middle::ty::query::Providers;
117 use rustc_middle::ty::subst::{InternalSubsts, Subst, SubstsRef};
118 use rustc_middle::ty::{self, Ty, TyCtxt, UserType};
119 use rustc_session::config;
120 use rustc_session::parse::feature_err;
121 use rustc_session::Session;
122 use rustc_span::source_map::DUMMY_SP;
123 use rustc_span::symbol::{kw, Ident};
124 use rustc_span::{self, BytePos, Span};
125 use rustc_target::abi::VariantIdx;
126 use rustc_target::spec::abi::Abi;
127 use rustc_trait_selection::traits;
128 use rustc_trait_selection::traits::error_reporting::recursive_type_with_infinite_size_error;
129 use rustc_trait_selection::traits::error_reporting::suggestions::ReturnsVisitor;
131 use std::cell::{Ref, RefCell, RefMut};
133 use crate::require_c_abi_if_c_variadic;
134 use crate::util::common::indenter;
136 use self::coercion::DynamicCoerceMany;
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 *providers = Providers {
246 diagnostic_only_typeck,
250 check_item_well_formed,
251 check_trait_item_well_formed,
252 check_impl_item_well_formed,
253 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, wf_tys) = 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(
379 &hir::Generics::empty(),
387 check_abi(tcx, id, span, fn_sig.abi());
389 // When normalizing the function signature, we assume all types are
390 // well-formed. So, we don't need to worry about the obligations
391 // from normalization. We could just discard these, but to align with
392 // compare_method and elsewhere, we just add implied bounds for
394 let mut wf_tys = FxHashSet::default();
395 // Compute the fty from point of view of inside the fn.
396 let fn_sig = tcx.liberate_late_bound_regions(def_id.to_def_id(), fn_sig);
397 let fn_sig = inh.normalize_associated_types_in(
403 wf_tys.extend(fn_sig.inputs_and_output.iter());
405 let fcx = check_fn(&inh, param_env, fn_sig, decl, id, body, None, true).0;
408 let fcx = FnCtxt::new(&inh, param_env, body.value.hir_id);
409 let expected_type = body_ty
410 .and_then(|ty| match ty.kind {
411 hir::TyKind::Infer => Some(<dyn AstConv<'_>>::ast_ty_to_ty(&fcx, ty)),
414 .unwrap_or_else(|| match tcx.hir().get(id) {
415 Node::AnonConst(_) => match tcx.hir().get(tcx.hir().get_parent_node(id)) {
416 Node::Expr(&hir::Expr {
417 kind: hir::ExprKind::ConstBlock(ref anon_const),
419 }) if anon_const.hir_id == id => fcx.next_ty_var(TypeVariableOrigin {
420 kind: TypeVariableOriginKind::TypeInference,
424 kind: hir::TyKind::Typeof(ref anon_const), ..
425 }) if anon_const.hir_id == id => fcx.next_ty_var(TypeVariableOrigin {
426 kind: TypeVariableOriginKind::TypeInference,
429 Node::Expr(&hir::Expr { kind: hir::ExprKind::InlineAsm(asm), .. })
430 | Node::Item(&hir::Item { kind: hir::ItemKind::GlobalAsm(asm), .. }) => {
434 .filter_map(|(op, _op_sp)| match op {
435 hir::InlineAsmOperand::Const { anon_const }
436 if anon_const.hir_id == id =>
438 // Inline assembly constants must be integers.
439 Some(fcx.next_int_var())
441 hir::InlineAsmOperand::SymFn { anon_const }
442 if anon_const.hir_id == id =>
444 Some(fcx.next_ty_var(TypeVariableOrigin {
445 kind: TypeVariableOriginKind::MiscVariable,
452 operand_ty.unwrap_or_else(fallback)
459 let expected_type = fcx.normalize_associated_types_in(body.value.span, expected_type);
460 fcx.require_type_is_sized(expected_type, body.value.span, traits::ConstSized);
462 // Gather locals in statics (because of block expressions).
463 GatherLocalsVisitor::new(&fcx).visit_body(body);
465 fcx.check_expr_coercable_to_type(&body.value, expected_type, None);
467 fcx.write_ty(id, expected_type);
469 (fcx, FxHashSet::default())
472 let fallback_has_occurred = fcx.type_inference_fallback();
474 // Even though coercion casts provide type hints, we check casts after fallback for
475 // backwards compatibility. This makes fallback a stronger type hint than a cast coercion.
477 fcx.select_obligations_where_possible(fallback_has_occurred, |_| {});
479 // Closure and generator analysis may run after fallback
480 // because they don't constrain other type variables.
481 fcx.closure_analyze(body);
482 assert!(fcx.deferred_call_resolutions.borrow().is_empty());
483 fcx.resolve_generator_interiors(def_id.to_def_id());
485 for (ty, span, code) in fcx.deferred_sized_obligations.borrow_mut().drain(..) {
486 let ty = fcx.normalize_ty(span, ty);
487 fcx.require_type_is_sized(ty, span, code);
490 fcx.select_all_obligations_or_error();
492 if fn_sig.is_some() {
493 fcx.regionck_fn(id, body, span, wf_tys);
495 fcx.regionck_expr(body);
498 fcx.resolve_type_vars_in_body(body)
501 // Consistency check our TypeckResults instance can hold all ItemLocalIds
502 // it will need to hold.
503 assert_eq!(typeck_results.hir_owner, id.owner);
508 /// When `check_fn` is invoked on a generator (i.e., a body that
509 /// includes yield), it returns back some information about the yield
511 struct GeneratorTypes<'tcx> {
512 /// Type of generator argument / values returned by `yield`.
515 /// Type of value that is yielded.
518 /// Types that are captured (see `GeneratorInterior` for more).
521 /// Indicates if the generator is movable or static (immovable).
522 movability: hir::Movability,
525 /// Given a `DefId` for an opaque type in return position, find its parent item's return
527 fn get_owner_return_paths<'tcx>(
530 ) -> Option<(LocalDefId, ReturnsVisitor<'tcx>)> {
531 let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
532 let parent_id = tcx.hir().get_parent_item(hir_id);
533 tcx.hir().find_by_def_id(parent_id).and_then(|node| node.body_id()).map(|body_id| {
534 let body = tcx.hir().body(body_id);
535 let mut visitor = ReturnsVisitor::default();
536 visitor.visit_body(body);
541 // Forbid defining intrinsics in Rust code,
542 // as they must always be defined by the compiler.
543 fn fn_maybe_err(tcx: TyCtxt<'_>, sp: Span, abi: Abi) {
544 if let Abi::RustIntrinsic | Abi::PlatformIntrinsic = abi {
545 tcx.sess.span_err(sp, "intrinsic must be in `extern \"rust-intrinsic\" { ... }` block");
549 fn maybe_check_static_with_link_section(tcx: TyCtxt<'_>, id: LocalDefId, span: Span) {
550 // Only restricted on wasm target for now
551 if !tcx.sess.target.is_like_wasm {
555 // If `#[link_section]` is missing, then nothing to verify
556 let attrs = tcx.codegen_fn_attrs(id);
557 if attrs.link_section.is_none() {
561 // For the wasm32 target statics with `#[link_section]` are placed into custom
562 // sections of the final output file, but this isn't link custom sections of
563 // other executable formats. Namely we can only embed a list of bytes,
564 // nothing with pointers to anything else or relocations. If any relocation
565 // show up, reject them here.
566 // `#[link_section]` may contain arbitrary, or even undefined bytes, but it is
567 // the consumer's responsibility to ensure all bytes that have been read
568 // have defined values.
569 if let Ok(alloc) = tcx.eval_static_initializer(id.to_def_id())
570 && alloc.inner().relocations().len() != 0
572 let msg = "statics with a custom `#[link_section]` must be a \
573 simple list of bytes on the wasm target with no \
574 extra levels of indirection such as references";
575 tcx.sess.span_err(span, msg);
579 fn report_forbidden_specialization(
581 impl_item: &hir::ImplItemRef,
584 let mut err = struct_span_err!(
588 "`{}` specializes an item from a parent `impl`, but \
589 that item is not marked `default`",
592 err.span_label(impl_item.span, format!("cannot specialize default item `{}`", impl_item.ident));
594 match tcx.span_of_impl(parent_impl) {
596 err.span_label(span, "parent `impl` is here");
598 "to specialize, `{}` in the parent `impl` must be marked `default`",
603 err.note(&format!("parent implementation is in crate `{cname}`"));
610 fn missing_items_err(
613 missing_items: &[&ty::AssocItem],
614 full_impl_span: Span,
616 let missing_items_msg = missing_items
618 .map(|trait_item| trait_item.name.to_string())
622 let mut err = struct_span_err!(
626 "not all trait items implemented, missing: `{missing_items_msg}`",
628 err.span_label(impl_span, format!("missing `{missing_items_msg}` in implementation"));
630 // `Span` before impl block closing brace.
631 let hi = full_impl_span.hi() - BytePos(1);
632 // Point at the place right before the closing brace of the relevant `impl` to suggest
633 // adding the associated item at the end of its body.
634 let sugg_sp = full_impl_span.with_lo(hi).with_hi(hi);
635 // Obtain the level of indentation ending in `sugg_sp`.
636 let indentation = tcx.sess.source_map().span_to_margin(sugg_sp).unwrap_or(0);
637 // Make the whitespace that will make the suggestion have the right indentation.
638 let padding: String = " ".repeat(indentation);
640 for trait_item in missing_items {
641 let snippet = suggestion_signature(trait_item, tcx);
642 let code = format!("{}{}\n{}", padding, snippet, padding);
643 let msg = format!("implement the missing item: `{snippet}`");
644 let appl = Applicability::HasPlaceholders;
645 if let Some(span) = tcx.hir().span_if_local(trait_item.def_id) {
646 err.span_label(span, format!("`{}` from trait", trait_item.name));
647 err.tool_only_span_suggestion(sugg_sp, &msg, code, appl);
649 err.span_suggestion_hidden(sugg_sp, &msg, code, appl);
655 fn missing_items_must_implement_one_of_err(
658 missing_items: &[Ident],
659 annotation_span: Option<Span>,
661 let missing_items_msg =
662 missing_items.iter().map(Ident::to_string).collect::<Vec<_>>().join("`, `");
664 let mut err = struct_span_err!(
668 "not all trait items implemented, missing one of: `{missing_items_msg}`",
670 err.span_label(impl_span, format!("missing one of `{missing_items_msg}` in implementation"));
672 if let Some(annotation_span) = annotation_span {
673 err.span_note(annotation_span, "required because of this annotation");
679 /// Re-sugar `ty::GenericPredicates` in a way suitable to be used in structured suggestions.
680 fn bounds_from_generic_predicates<'tcx>(
682 predicates: ty::GenericPredicates<'tcx>,
683 ) -> (String, String) {
684 let mut types: FxHashMap<Ty<'tcx>, Vec<DefId>> = FxHashMap::default();
685 let mut projections = vec![];
686 for (predicate, _) in predicates.predicates {
687 debug!("predicate {:?}", predicate);
688 let bound_predicate = predicate.kind();
689 match bound_predicate.skip_binder() {
690 ty::PredicateKind::Trait(trait_predicate) => {
691 let entry = types.entry(trait_predicate.self_ty()).or_default();
692 let def_id = trait_predicate.def_id();
693 if Some(def_id) != tcx.lang_items().sized_trait() {
694 // Type params are `Sized` by default, do not add that restriction to the list
695 // if it is a positive requirement.
696 entry.push(trait_predicate.def_id());
699 ty::PredicateKind::Projection(projection_pred) => {
700 projections.push(bound_predicate.rebind(projection_pred));
705 let generics = if types.is_empty() {
712 .filter_map(|t| match t.kind() {
713 ty::Param(_) => Some(t.to_string()),
714 // Avoid suggesting the following:
715 // fn foo<T, <T as Trait>::Bar>(_: T) where T: Trait, <T as Trait>::Bar: Other {}
722 let mut where_clauses = vec![];
723 for (ty, bounds) in types {
725 .extend(bounds.into_iter().map(|bound| format!("{}: {}", ty, tcx.def_path_str(bound))));
727 for projection in &projections {
728 let p = projection.skip_binder();
729 // FIXME: this is not currently supported syntax, we should be looking at the `types` and
730 // insert the associated types where they correspond, but for now let's be "lazy" and
731 // propose this instead of the following valid resugaring:
732 // `T: Trait, Trait::Assoc = K` → `T: Trait<Assoc = K>`
733 where_clauses.push(format!(
735 tcx.def_path_str(p.projection_ty.item_def_id),
739 let where_clauses = if where_clauses.is_empty() {
742 format!(" where {}", where_clauses.join(", "))
744 (generics, where_clauses)
747 /// Return placeholder code for the given function.
748 fn fn_sig_suggestion<'tcx>(
750 sig: ty::FnSig<'tcx>,
752 predicates: ty::GenericPredicates<'tcx>,
753 assoc: &ty::AssocItem,
760 Some(match ty.kind() {
761 ty::Param(_) if assoc.fn_has_self_parameter && i == 0 => "self".to_string(),
762 ty::Ref(reg, ref_ty, mutability) if i == 0 => {
763 let reg = format!("{reg} ");
764 let reg = match ®[..] {
768 if assoc.fn_has_self_parameter {
769 match ref_ty.kind() {
770 ty::Param(param) if param.name == kw::SelfUpper => {
771 format!("&{}{}self", reg, mutability.prefix_str())
774 _ => format!("self: {ty}"),
781 if assoc.fn_has_self_parameter && i == 0 {
782 format!("self: {ty}")
789 .chain(std::iter::once(if sig.c_variadic { Some("...".to_string()) } else { None }))
791 .collect::<Vec<String>>()
793 let output = sig.output();
794 let output = if !output.is_unit() { format!(" -> {output}") } else { String::new() };
796 let unsafety = sig.unsafety.prefix_str();
797 let (generics, where_clauses) = bounds_from_generic_predicates(tcx, predicates);
799 // FIXME: this is not entirely correct, as the lifetimes from borrowed params will
800 // not be present in the `fn` definition, not will we account for renamed
801 // lifetimes between the `impl` and the `trait`, but this should be good enough to
802 // fill in a significant portion of the missing code, and other subsequent
803 // suggestions can help the user fix the code.
804 format!("{unsafety}fn {ident}{generics}({args}){output}{where_clauses} {{ todo!() }}")
807 /// Return placeholder code for the given associated item.
808 /// Similar to `ty::AssocItem::suggestion`, but appropriate for use as the code snippet of a
809 /// structured suggestion.
810 fn suggestion_signature(assoc: &ty::AssocItem, tcx: TyCtxt<'_>) -> String {
812 ty::AssocKind::Fn => {
813 // We skip the binder here because the binder would deanonymize all
814 // late-bound regions, and we don't want method signatures to show up
815 // `as for<'r> fn(&'r MyType)`. Pretty-printing handles late-bound
816 // regions just fine, showing `fn(&MyType)`.
819 tcx.fn_sig(assoc.def_id).skip_binder(),
821 tcx.predicates_of(assoc.def_id),
825 ty::AssocKind::Type => format!("type {} = Type;", assoc.name),
826 ty::AssocKind::Const => {
827 let ty = tcx.type_of(assoc.def_id);
828 let val = expr::ty_kind_suggestion(ty).unwrap_or("value");
829 format!("const {}: {} = {};", assoc.name, ty, val)
834 /// Emit an error when encountering two or more variants in a transparent enum.
835 fn bad_variant_count<'tcx>(tcx: TyCtxt<'tcx>, adt: ty::AdtDef<'tcx>, sp: Span, did: DefId) {
836 let variant_spans: Vec<_> = adt
839 .map(|variant| tcx.hir().span_if_local(variant.def_id).unwrap())
841 let msg = format!("needs exactly one variant, but has {}", adt.variants().len(),);
842 let mut err = struct_span_err!(tcx.sess, sp, E0731, "transparent enum {msg}");
843 err.span_label(sp, &msg);
844 if let [start @ .., end] = &*variant_spans {
845 for variant_span in start {
846 err.span_label(*variant_span, "");
848 err.span_label(*end, &format!("too many variants in `{}`", tcx.def_path_str(did)));
853 /// Emit an error when encountering two or more non-zero-sized fields in a transparent
855 fn bad_non_zero_sized_fields<'tcx>(
857 adt: ty::AdtDef<'tcx>,
859 field_spans: impl Iterator<Item = Span>,
862 let msg = format!("needs at most one non-zero-sized field, but has {field_count}");
863 let mut err = struct_span_err!(
867 "{}transparent {} {}",
868 if adt.is_enum() { "the variant of a " } else { "" },
872 err.span_label(sp, &msg);
873 for sp in field_spans {
874 err.span_label(sp, "this field is non-zero-sized");
879 fn report_unexpected_variant_res(tcx: TyCtxt<'_>, res: Res, span: Span) {
884 "expected unit struct, unit variant or constant, found {}{}",
888 .span_to_snippet(span)
889 .map_or_else(|_| String::new(), |s| format!(" `{s}`",)),
894 /// Controls whether the arguments are tupled. This is used for the call
897 /// Tupling means that all call-side arguments are packed into a tuple and
898 /// passed as a single parameter. For example, if tupling is enabled, this
901 /// fn f(x: (isize, isize))
903 /// Can be called as:
910 #[derive(Clone, Eq, PartialEq)]
911 enum TupleArgumentsFlag {
916 /// A wrapper for `InferCtxt`'s `in_progress_typeck_results` field.
917 #[derive(Copy, Clone)]
918 struct MaybeInProgressTables<'a, 'tcx> {
919 maybe_typeck_results: Option<&'a RefCell<ty::TypeckResults<'tcx>>>,
922 impl<'a, 'tcx> MaybeInProgressTables<'a, 'tcx> {
923 fn borrow(self) -> Ref<'a, ty::TypeckResults<'tcx>> {
924 match self.maybe_typeck_results {
925 Some(typeck_results) => typeck_results.borrow(),
927 "MaybeInProgressTables: inh/fcx.typeck_results.borrow() with no typeck results"
932 fn borrow_mut(self) -> RefMut<'a, ty::TypeckResults<'tcx>> {
933 match self.maybe_typeck_results {
934 Some(typeck_results) => typeck_results.borrow_mut(),
936 "MaybeInProgressTables: inh/fcx.typeck_results.borrow_mut() with no typeck results"
942 struct CheckItemTypesVisitor<'tcx> {
946 impl<'tcx> ItemLikeVisitor<'tcx> for CheckItemTypesVisitor<'tcx> {
947 fn visit_item(&mut self, i: &'tcx hir::Item<'tcx>) {
948 check_item_type(self.tcx, i);
950 fn visit_trait_item(&mut self, _: &'tcx hir::TraitItem<'tcx>) {}
951 fn visit_impl_item(&mut self, _: &'tcx hir::ImplItem<'tcx>) {}
952 fn visit_foreign_item(&mut self, _: &'tcx hir::ForeignItem<'tcx>) {}
955 fn typeck_item_bodies(tcx: TyCtxt<'_>, (): ()) {
956 tcx.hir().par_body_owners(|body_owner_def_id| tcx.ensure().typeck(body_owner_def_id));
959 fn fatally_break_rust(sess: &Session) {
960 let handler = sess.diagnostic();
961 handler.span_bug_no_panic(
963 "It looks like you're trying to break rust; would you like some ICE?",
965 handler.note_without_error("the compiler expectedly panicked. this is a feature.");
966 handler.note_without_error(
967 "we would appreciate a joke overview: \
968 https://github.com/rust-lang/rust/issues/43162#issuecomment-320764675",
970 handler.note_without_error(&format!(
971 "rustc {} running on {}",
972 option_env!("CFG_VERSION").unwrap_or("unknown_version"),
973 config::host_triple(),
977 fn potentially_plural_count(count: usize, word: &str) -> String {
978 format!("{} {}{}", count, word, pluralize!(count))
981 fn has_expected_num_generic_args<'tcx>(
983 trait_did: Option<DefId>,
986 trait_did.map_or(true, |trait_did| {
987 let generics = tcx.generics_of(trait_did);
988 generics.count() == expected + if generics.has_self { 1 } else { 0 }