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};
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, MultiSpan, 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 if $typ.references_error() {
143 $session.diagnostic().struct_dummy()
145 rustc_errors::struct_span_err!($session, $span, $code, $($message)*)
150 /// The type of a local binding, including the revealed type for anon types.
151 #[derive(Copy, Clone, Debug)]
152 pub struct LocalTy<'tcx> {
154 revealed_ty: Ty<'tcx>,
157 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
164 fn maybe_mut_place(m: hir::Mutability) -> Self {
166 hir::Mutability::Mut => Needs::MutPlace,
167 hir::Mutability::Not => Needs::None,
172 #[derive(Copy, Clone)]
173 pub struct UnsafetyState {
175 pub unsafety: hir::Unsafety,
180 pub fn function(unsafety: hir::Unsafety, def: hir::HirId) -> UnsafetyState {
181 UnsafetyState { def, unsafety, from_fn: true }
184 pub fn recurse(self, blk: &hir::Block<'_>) -> UnsafetyState {
185 use hir::BlockCheckMode;
186 match self.unsafety {
187 // If this unsafe, then if the outer function was already marked as
188 // unsafe we shouldn't attribute the unsafe'ness to the block. This
189 // way the block can be warned about instead of ignoring this
190 // extraneous block (functions are never warned about).
191 hir::Unsafety::Unsafe if self.from_fn => self,
194 let (unsafety, def) = match blk.rules {
195 BlockCheckMode::UnsafeBlock(..) => (hir::Unsafety::Unsafe, blk.hir_id),
196 BlockCheckMode::DefaultBlock => (unsafety, self.def),
198 UnsafetyState { def, unsafety, from_fn: false }
204 #[derive(Debug, Copy, Clone)]
210 pub struct BreakableCtxt<'tcx> {
213 // this is `null` for loops where break with a value is illegal,
214 // such as `while`, `for`, and `while let`
215 coerce: Option<DynamicCoerceMany<'tcx>>,
218 pub struct EnclosingBreakables<'tcx> {
219 stack: Vec<BreakableCtxt<'tcx>>,
220 by_id: HirIdMap<usize>,
223 impl<'tcx> EnclosingBreakables<'tcx> {
224 fn find_breakable(&mut self, target_id: hir::HirId) -> &mut BreakableCtxt<'tcx> {
225 self.opt_find_breakable(target_id).unwrap_or_else(|| {
226 bug!("could not find enclosing breakable with id {}", target_id);
230 fn opt_find_breakable(&mut self, target_id: hir::HirId) -> Option<&mut BreakableCtxt<'tcx>> {
231 match self.by_id.get(&target_id) {
232 Some(ix) => Some(&mut self.stack[*ix]),
238 pub fn provide(providers: &mut Providers) {
239 method::provide(providers);
240 *providers = Providers {
244 diagnostic_only_typeck,
248 check_item_well_formed,
249 check_trait_item_well_formed,
250 check_impl_item_well_formed,
251 check_mod_item_types,
256 fn adt_destructor(tcx: TyCtxt<'_>, def_id: DefId) -> Option<ty::Destructor> {
257 tcx.calculate_dtor(def_id, dropck::check_drop_impl)
260 /// If this `DefId` is a "primary tables entry", returns
261 /// `Some((body_id, body_ty, fn_sig))`. Otherwise, returns `None`.
263 /// If this function returns `Some`, then `typeck_results(def_id)` will
264 /// succeed; if it returns `None`, then `typeck_results(def_id)` may or
265 /// may not succeed. In some cases where this function returns `None`
266 /// (notably closures), `typeck_results(def_id)` would wind up
267 /// redirecting to the owning function.
271 ) -> Option<(hir::BodyId, Option<&hir::Ty<'_>>, Option<&hir::FnSig<'_>>)> {
272 match tcx.hir().get(id) {
273 Node::Item(item) => match item.kind {
274 hir::ItemKind::Const(ty, body) | hir::ItemKind::Static(ty, _, body) => {
275 Some((body, Some(ty), None))
277 hir::ItemKind::Fn(ref sig, .., body) => Some((body, None, Some(sig))),
280 Node::TraitItem(item) => match item.kind {
281 hir::TraitItemKind::Const(ty, Some(body)) => Some((body, Some(ty), None)),
282 hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Provided(body)) => {
283 Some((body, None, Some(sig)))
287 Node::ImplItem(item) => match item.kind {
288 hir::ImplItemKind::Const(ty, body) => Some((body, Some(ty), None)),
289 hir::ImplItemKind::Fn(ref sig, body) => Some((body, None, Some(sig))),
292 Node::AnonConst(constant) => Some((constant.body, None, None)),
297 fn has_typeck_results(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
298 // Closures' typeck results come from their outermost function,
299 // as they are part of the same "inference environment".
300 let typeck_root_def_id = tcx.typeck_root_def_id(def_id);
301 if typeck_root_def_id != def_id {
302 return tcx.has_typeck_results(typeck_root_def_id);
305 if let Some(def_id) = def_id.as_local() {
306 let id = tcx.hir().local_def_id_to_hir_id(def_id);
307 primary_body_of(tcx, id).is_some()
313 fn used_trait_imports(tcx: TyCtxt<'_>, def_id: LocalDefId) -> &FxHashSet<LocalDefId> {
314 &*tcx.typeck(def_id).used_trait_imports
317 fn typeck_const_arg<'tcx>(
319 (did, param_did): (LocalDefId, DefId),
320 ) -> &ty::TypeckResults<'tcx> {
321 let fallback = move || tcx.type_of(param_did);
322 typeck_with_fallback(tcx, did, fallback)
325 fn typeck<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &ty::TypeckResults<'tcx> {
326 if let Some(param_did) = tcx.opt_const_param_of(def_id) {
327 tcx.typeck_const_arg((def_id, param_did))
329 let fallback = move || tcx.type_of(def_id.to_def_id());
330 typeck_with_fallback(tcx, def_id, fallback)
334 /// Used only to get `TypeckResults` for type inference during error recovery.
335 /// Currently only used for type inference of `static`s and `const`s to avoid type cycle errors.
336 fn diagnostic_only_typeck<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &ty::TypeckResults<'tcx> {
337 let fallback = move || {
338 let span = tcx.hir().span(tcx.hir().local_def_id_to_hir_id(def_id));
339 tcx.ty_error_with_message(span, "diagnostic only typeck table used")
341 typeck_with_fallback(tcx, def_id, fallback)
344 #[instrument(skip(tcx, fallback))]
345 fn typeck_with_fallback<'tcx>(
348 fallback: impl Fn() -> Ty<'tcx> + 'tcx,
349 ) -> &'tcx ty::TypeckResults<'tcx> {
350 // Closures' typeck results come from their outermost function,
351 // as they are part of the same "inference environment".
352 let typeck_root_def_id = tcx.typeck_root_def_id(def_id.to_def_id()).expect_local();
353 if typeck_root_def_id != def_id {
354 return tcx.typeck(typeck_root_def_id);
357 let id = tcx.hir().local_def_id_to_hir_id(def_id);
358 let span = tcx.hir().span(id);
360 // Figure out what primary body this item has.
361 let (body_id, body_ty, fn_sig) = primary_body_of(tcx, id).unwrap_or_else(|| {
362 span_bug!(span, "can't type-check body of {:?}", def_id);
364 let body = tcx.hir().body(body_id);
366 let typeck_results = Inherited::build(tcx, def_id).enter(|inh| {
367 let param_env = tcx.param_env(def_id);
368 let (fcx, wf_tys) = if let Some(hir::FnSig { header, decl, .. }) = fn_sig {
369 let fn_sig = if crate::collect::get_infer_ret_ty(&decl.output).is_some() {
370 let fcx = FnCtxt::new(&inh, param_env, body.value.hir_id);
371 <dyn AstConv<'_>>::ty_of_fn(
377 &hir::Generics::empty(),
385 check_abi(tcx, id, span, fn_sig.abi());
387 // When normalizing the function signature, we assume all types are
388 // well-formed. So, we don't need to worry about the obligations
389 // from normalization. We could just discard these, but to align with
390 // compare_method and elsewhere, we just add implied bounds for
392 let mut wf_tys = FxHashSet::default();
393 // Compute the fty from point of view of inside the fn.
394 let fn_sig = tcx.liberate_late_bound_regions(def_id.to_def_id(), fn_sig);
395 let fn_sig = inh.normalize_associated_types_in(
401 wf_tys.extend(fn_sig.inputs_and_output.iter());
403 let fcx = check_fn(&inh, param_env, fn_sig, decl, id, body, None, true).0;
406 let fcx = FnCtxt::new(&inh, param_env, body.value.hir_id);
407 let expected_type = body_ty
408 .and_then(|ty| match ty.kind {
409 hir::TyKind::Infer => Some(<dyn AstConv<'_>>::ast_ty_to_ty(&fcx, ty)),
412 .unwrap_or_else(|| match tcx.hir().get(id) {
413 Node::AnonConst(_) => match tcx.hir().get(tcx.hir().get_parent_node(id)) {
414 Node::Expr(&hir::Expr {
415 kind: hir::ExprKind::ConstBlock(ref anon_const),
417 }) if anon_const.hir_id == id => fcx.next_ty_var(TypeVariableOrigin {
418 kind: TypeVariableOriginKind::TypeInference,
422 kind: hir::TyKind::Typeof(ref anon_const), ..
423 }) if anon_const.hir_id == id => fcx.next_ty_var(TypeVariableOrigin {
424 kind: TypeVariableOriginKind::TypeInference,
427 Node::Expr(&hir::Expr { kind: hir::ExprKind::InlineAsm(asm), .. })
428 | Node::Item(&hir::Item { kind: hir::ItemKind::GlobalAsm(asm), .. })
429 if asm.operands.iter().any(|(op, _op_sp)| match op {
430 hir::InlineAsmOperand::Const { anon_const } => {
431 anon_const.hir_id == id
436 // Inline assembly constants must be integers.
444 let expected_type = fcx.normalize_associated_types_in(body.value.span, expected_type);
445 fcx.require_type_is_sized(expected_type, body.value.span, traits::ConstSized);
447 // Gather locals in statics (because of block expressions).
448 GatherLocalsVisitor::new(&fcx).visit_body(body);
450 fcx.check_expr_coercable_to_type(&body.value, expected_type, None);
452 fcx.write_ty(id, expected_type);
454 (fcx, FxHashSet::default())
457 let fallback_has_occurred = fcx.type_inference_fallback();
459 // Even though coercion casts provide type hints, we check casts after fallback for
460 // backwards compatibility. This makes fallback a stronger type hint than a cast coercion.
462 fcx.select_obligations_where_possible(fallback_has_occurred, |_| {});
464 // Closure and generator analysis may run after fallback
465 // because they don't constrain other type variables.
466 fcx.closure_analyze(body);
467 assert!(fcx.deferred_call_resolutions.borrow().is_empty());
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 fn_sig.is_some() {
478 fcx.regionck_fn(id, body, span, wf_tys);
480 fcx.regionck_expr(body);
483 fcx.resolve_type_vars_in_body(body)
486 // Consistency check our TypeckResults instance can hold all ItemLocalIds
487 // it will need to hold.
488 assert_eq!(typeck_results.hir_owner, id.owner);
493 /// When `check_fn` is invoked on a generator (i.e., a body that
494 /// includes yield), it returns back some information about the yield
496 struct GeneratorTypes<'tcx> {
497 /// Type of generator argument / values returned by `yield`.
500 /// Type of value that is yielded.
503 /// Types that are captured (see `GeneratorInterior` for more).
506 /// Indicates if the generator is movable or static (immovable).
507 movability: hir::Movability,
510 /// Given a `DefId` for an opaque type in return position, find its parent item's return
512 fn get_owner_return_paths<'tcx>(
515 ) -> Option<(LocalDefId, ReturnsVisitor<'tcx>)> {
516 let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
517 let parent_id = tcx.hir().get_parent_item(hir_id);
518 tcx.hir().find_by_def_id(parent_id).and_then(|node| node.body_id()).map(|body_id| {
519 let body = tcx.hir().body(body_id);
520 let mut visitor = ReturnsVisitor::default();
521 visitor.visit_body(body);
526 // Forbid defining intrinsics in Rust code,
527 // as they must always be defined by the compiler.
528 fn fn_maybe_err(tcx: TyCtxt<'_>, sp: Span, abi: Abi) {
529 if let Abi::RustIntrinsic | Abi::PlatformIntrinsic = abi {
530 tcx.sess.span_err(sp, "intrinsic must be in `extern \"rust-intrinsic\" { ... }` block");
534 fn maybe_check_static_with_link_section(tcx: TyCtxt<'_>, id: LocalDefId, span: Span) {
535 // Only restricted on wasm target for now
536 if !tcx.sess.target.is_like_wasm {
540 // If `#[link_section]` is missing, then nothing to verify
541 let attrs = tcx.codegen_fn_attrs(id);
542 if attrs.link_section.is_none() {
546 // For the wasm32 target statics with `#[link_section]` are placed into custom
547 // sections of the final output file, but this isn't link custom sections of
548 // other executable formats. Namely we can only embed a list of bytes,
549 // nothing with pointers to anything else or relocations. If any relocation
550 // show up, reject them here.
551 // `#[link_section]` may contain arbitrary, or even undefined bytes, but it is
552 // the consumer's responsibility to ensure all bytes that have been read
553 // have defined values.
554 if let Ok(alloc) = tcx.eval_static_initializer(id.to_def_id()) {
555 if alloc.relocations().len() != 0 {
556 let msg = "statics with a custom `#[link_section]` must be a \
557 simple list of bytes on the wasm target with no \
558 extra levels of indirection such as references";
559 tcx.sess.span_err(span, msg);
564 fn report_forbidden_specialization(
566 impl_item: &hir::ImplItemRef,
569 let mut err = struct_span_err!(
573 "`{}` specializes an item from a parent `impl`, but \
574 that item is not marked `default`",
577 err.span_label(impl_item.span, format!("cannot specialize default item `{}`", impl_item.ident));
579 match tcx.span_of_impl(parent_impl) {
581 err.span_label(span, "parent `impl` is here");
583 "to specialize, `{}` in the parent `impl` must be marked `default`",
588 err.note(&format!("parent implementation is in crate `{}`", cname));
595 fn missing_items_err(
598 missing_items: &[&ty::AssocItem],
599 full_impl_span: Span,
601 let missing_items_msg = missing_items
603 .map(|trait_item| trait_item.name.to_string())
607 let mut err = struct_span_err!(
611 "not all trait items implemented, missing: `{}`",
614 err.span_label(impl_span, format!("missing `{}` in implementation", missing_items_msg));
616 // `Span` before impl block closing brace.
617 let hi = full_impl_span.hi() - BytePos(1);
618 // Point at the place right before the closing brace of the relevant `impl` to suggest
619 // adding the associated item at the end of its body.
620 let sugg_sp = full_impl_span.with_lo(hi).with_hi(hi);
621 // Obtain the level of indentation ending in `sugg_sp`.
622 let indentation = tcx.sess.source_map().span_to_margin(sugg_sp).unwrap_or(0);
623 // Make the whitespace that will make the suggestion have the right indentation.
624 let padding: String = " ".repeat(indentation);
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: `{}`",
657 err.span_label(impl_span, format!("missing one of `{}` in implementation", missing_items_msg));
659 if let Some(annotation_span) = annotation_span {
660 err.span_note(annotation_span, "required because of this annotation");
666 /// Resugar `ty::GenericPredicates` in a way suitable to be used in structured suggestions.
667 fn bounds_from_generic_predicates<'tcx>(
669 predicates: ty::GenericPredicates<'tcx>,
670 ) -> (String, String) {
671 let mut types: FxHashMap<Ty<'tcx>, Vec<DefId>> = FxHashMap::default();
672 let mut projections = vec![];
673 for (predicate, _) in predicates.predicates {
674 debug!("predicate {:?}", predicate);
675 let bound_predicate = predicate.kind();
676 match bound_predicate.skip_binder() {
677 ty::PredicateKind::Trait(trait_predicate) => {
678 let entry = types.entry(trait_predicate.self_ty()).or_default();
679 let def_id = trait_predicate.def_id();
680 if Some(def_id) != tcx.lang_items().sized_trait() {
681 // Type params are `Sized` by default, do not add that restriction to the list
682 // if it is a positive requirement.
683 entry.push(trait_predicate.def_id());
686 ty::PredicateKind::Projection(projection_pred) => {
687 projections.push(bound_predicate.rebind(projection_pred));
692 let generics = if types.is_empty() {
699 .filter_map(|t| match t.kind() {
700 ty::Param(_) => Some(t.to_string()),
701 // Avoid suggesting the following:
702 // fn foo<T, <T as Trait>::Bar>(_: T) where T: Trait, <T as Trait>::Bar: Other {}
709 let mut where_clauses = vec![];
710 for (ty, bounds) in types {
712 .extend(bounds.into_iter().map(|bound| format!("{}: {}", ty, tcx.def_path_str(bound))));
714 for projection in &projections {
715 let p = projection.skip_binder();
716 // FIXME: this is not currently supported syntax, we should be looking at the `types` and
717 // insert the associated types where they correspond, but for now let's be "lazy" and
718 // propose this instead of the following valid resugaring:
719 // `T: Trait, Trait::Assoc = K` → `T: Trait<Assoc = K>`
720 where_clauses.push(format!(
722 tcx.def_path_str(p.projection_ty.item_def_id),
726 let where_clauses = if where_clauses.is_empty() {
729 format!(" where {}", where_clauses.join(", "))
731 (generics, where_clauses)
734 /// Return placeholder code for the given function.
735 fn fn_sig_suggestion<'tcx>(
737 sig: ty::FnSig<'tcx>,
739 predicates: ty::GenericPredicates<'tcx>,
740 assoc: &ty::AssocItem,
747 Some(match ty.kind() {
748 ty::Param(_) if assoc.fn_has_self_parameter && i == 0 => "self".to_string(),
749 ty::Ref(reg, ref_ty, mutability) if i == 0 => {
750 let reg = match &format!("{}", reg)[..] {
751 "'_" | "" => String::new(),
752 reg => format!("{} ", reg),
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.
791 "{}fn {}{}({}){}{} {{ todo!() }}",
792 unsafety, ident, generics, args, output, where_clauses
796 /// Return placeholder code for the given associated item.
797 /// Similar to `ty::AssocItem::suggestion`, but appropriate for use as the code snippet of a
798 /// structured suggestion.
799 fn suggestion_signature(assoc: &ty::AssocItem, tcx: TyCtxt<'_>) -> String {
801 ty::AssocKind::Fn => {
802 // We skip the binder here because the binder would deanonymize all
803 // late-bound regions, and we don't want method signatures to show up
804 // `as for<'r> fn(&'r MyType)`. Pretty-printing handles late-bound
805 // regions just fine, showing `fn(&MyType)`.
808 tcx.fn_sig(assoc.def_id).skip_binder(),
810 tcx.predicates_of(assoc.def_id),
814 ty::AssocKind::Type => format!("type {} = Type;", assoc.name),
815 ty::AssocKind::Const => {
816 let ty = tcx.type_of(assoc.def_id);
817 let val = expr::ty_kind_suggestion(ty).unwrap_or("value");
818 format!("const {}: {} = {};", assoc.name, ty, val)
823 /// Emit an error when encountering two or more variants in a transparent enum.
824 fn bad_variant_count<'tcx>(tcx: TyCtxt<'tcx>, adt: &'tcx ty::AdtDef, sp: Span, did: DefId) {
825 let variant_spans: Vec<_> = adt
828 .map(|variant| tcx.hir().span_if_local(variant.def_id).unwrap())
830 let msg = format!("needs exactly one variant, but has {}", adt.variants.len(),);
831 let mut err = struct_span_err!(tcx.sess, sp, E0731, "transparent enum {}", msg);
832 err.span_label(sp, &msg);
833 if let [start @ .., end] = &*variant_spans {
834 for variant_span in start {
835 err.span_label(*variant_span, "");
837 err.span_label(*end, &format!("too many variants in `{}`", tcx.def_path_str(did)));
842 /// Emit an error when encountering two or more non-zero-sized fields in a transparent
844 fn bad_non_zero_sized_fields<'tcx>(
846 adt: &'tcx ty::AdtDef,
848 field_spans: impl Iterator<Item = Span>,
851 let msg = format!("needs at most one non-zero-sized field, but has {}", field_count);
852 let mut err = struct_span_err!(
856 "{}transparent {} {}",
857 if adt.is_enum() { "the variant of a " } else { "" },
861 err.span_label(sp, &msg);
862 for sp in field_spans {
863 err.span_label(sp, "this field is non-zero-sized");
868 fn report_unexpected_variant_res(tcx: TyCtxt<'_>, res: Res, span: Span) {
873 "expected unit struct, unit variant or constant, found {}{}",
877 .span_to_snippet(span)
878 .map_or_else(|_| String::new(), |s| format!(" `{}`", s)),
883 /// Controls whether the arguments are tupled. This is used for the call
886 /// Tupling means that all call-side arguments are packed into a tuple and
887 /// passed as a single parameter. For example, if tupling is enabled, this
890 /// fn f(x: (isize, isize))
892 /// Can be called as:
899 #[derive(Clone, Eq, PartialEq)]
900 enum TupleArgumentsFlag {
905 /// A wrapper for `InferCtxt`'s `in_progress_typeck_results` field.
906 #[derive(Copy, Clone)]
907 struct MaybeInProgressTables<'a, 'tcx> {
908 maybe_typeck_results: Option<&'a RefCell<ty::TypeckResults<'tcx>>>,
911 impl<'a, 'tcx> MaybeInProgressTables<'a, 'tcx> {
912 fn borrow(self) -> Ref<'a, ty::TypeckResults<'tcx>> {
913 match self.maybe_typeck_results {
914 Some(typeck_results) => typeck_results.borrow(),
916 "MaybeInProgressTables: inh/fcx.typeck_results.borrow() with no typeck results"
921 fn borrow_mut(self) -> RefMut<'a, ty::TypeckResults<'tcx>> {
922 match self.maybe_typeck_results {
923 Some(typeck_results) => typeck_results.borrow_mut(),
925 "MaybeInProgressTables: inh/fcx.typeck_results.borrow_mut() with no typeck results"
931 struct CheckItemTypesVisitor<'tcx> {
935 impl<'tcx> ItemLikeVisitor<'tcx> for CheckItemTypesVisitor<'tcx> {
936 fn visit_item(&mut self, i: &'tcx hir::Item<'tcx>) {
937 check_item_type(self.tcx, i);
939 fn visit_trait_item(&mut self, _: &'tcx hir::TraitItem<'tcx>) {}
940 fn visit_impl_item(&mut self, _: &'tcx hir::ImplItem<'tcx>) {}
941 fn visit_foreign_item(&mut self, _: &'tcx hir::ForeignItem<'tcx>) {}
944 fn typeck_item_bodies(tcx: TyCtxt<'_>, (): ()) {
945 tcx.hir().par_body_owners(|body_owner_def_id| tcx.ensure().typeck(body_owner_def_id));
948 fn fatally_break_rust(sess: &Session) {
949 let handler = sess.diagnostic();
950 handler.span_bug_no_panic(
952 "It looks like you're trying to break rust; would you like some ICE?",
954 handler.note_without_error("the compiler expectedly panicked. this is a feature.");
955 handler.note_without_error(
956 "we would appreciate a joke overview: \
957 https://github.com/rust-lang/rust/issues/43162#issuecomment-320764675",
959 handler.note_without_error(&format!(
960 "rustc {} running on {}",
961 option_env!("CFG_VERSION").unwrap_or("unknown_version"),
962 config::host_triple(),
966 fn potentially_plural_count(count: usize, word: &str) -> String {
967 format!("{} {}{}", count, word, pluralize!(count))
970 fn has_expected_num_generic_args<'tcx>(
972 trait_did: Option<DefId>,
975 trait_did.map_or(true, |trait_did| {
976 let generics = tcx.generics_of(trait_did);
977 generics.count() == expected + if generics.has_self { 1 } else { 0 }