Skip to main content

rustc_hir_analysis/check/
mod.rs

1/*!
2
3# typeck: check phase
4
5Within 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
7function). Inference is used to supply types wherever they are unknown.
8
9By far the most complex case is checking the body of a function. This
10can be broken down into several distinct phases:
11
12- gather: creates type variables to represent the type of each local
13  variable and pattern binding.
14
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.
20
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.
25
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
30  flexibility.
31
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.
36
37## Intermediate types
38
39While type checking a function, the intermediate types for the
40expressions, blocks, and so forth contained within the function are
41stored in `fcx.node_types` and `fcx.node_args`. These types
42may contain unresolved type variables. After type checking is
43complete, the functions in the writeback module are used to take the
44types from this table, resolve them, and then write them into their
45permanent home in the type context `tcx`.
46
47This means that during inferencing you should use `fcx.write_ty()`
48and `fcx.expr_ty()` / `fcx.node_ty()` to write/obtain the types of
49nodes within the function.
50
51The types of top-level items, which never contain unbound type
52variables, are stored directly into the `tcx` typeck_results.
53
54N.B., a type variable is not the same thing as a type parameter. A
55type variable is an instance of a type parameter. That is,
56given a generic function `fn foo<T>(t: T)`, while checking the
57function `foo`, the type `ty_param(0)` refers to the type `T`, which
58is treated in abstract. However, when `foo()` is called, `T` will be
59instantiated with a fresh type variable `N`. This variable will
60eventually be resolved to some concrete type (which might itself be
61a type parameter).
62
63*/
64
65pub mod always_applicable;
66mod check;
67mod compare_eii;
68mod compare_impl_item;
69mod entry;
70pub mod intrinsic;
71mod region;
72pub mod wfcheck;
73
74use std::borrow::Cow;
75use std::num::NonZero;
76
77pub use check::{check_abi, check_custom_abi};
78use rustc_abi::VariantIdx;
79use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
80use rustc_errors::{Diag, ErrorGuaranteed, pluralize, struct_span_code_err};
81use rustc_hir::LangItem;
82use rustc_hir::def_id::{DefId, LocalDefId};
83use rustc_hir::intravisit::Visitor;
84use rustc_index::bit_set::DenseBitSet;
85use rustc_infer::infer::{self, TyCtxtInferExt as _};
86use rustc_infer::traits::ObligationCause;
87use rustc_middle::query::Providers;
88use rustc_middle::ty::error::{ExpectedFound, TypeError};
89use rustc_middle::ty::print::with_types_for_signature;
90use rustc_middle::ty::{
91    self, GenericArgs, GenericArgsRef, OutlivesPredicate, Region, Ty, TyCtxt, TypingMode,
92};
93use rustc_middle::{bug, span_bug};
94use rustc_session::parse::feature_err;
95use rustc_span::def_id::CRATE_DEF_ID;
96use rustc_span::{BytePos, DUMMY_SP, Ident, Span, Symbol, kw, sym};
97use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
98use rustc_trait_selection::error_reporting::infer::ObligationCauseExt as _;
99use rustc_trait_selection::error_reporting::traits::suggestions::ReturnsVisitor;
100use rustc_trait_selection::traits::ObligationCtxt;
101use tracing::debug;
102
103use self::compare_impl_item::collect_return_position_impl_trait_in_trait_tys;
104use self::region::region_scope_tree;
105use crate::{check_c_variadic_abi, errors};
106
107/// Adds query implementations to the [Providers] vtable, see [`rustc_middle::query`]
108pub(super) fn provide(providers: &mut Providers) {
109    *providers = Providers {
110        adt_destructor,
111        adt_async_destructor,
112        region_scope_tree,
113        collect_return_position_impl_trait_in_trait_tys,
114        compare_impl_item: compare_impl_item::compare_impl_item,
115        check_coroutine_obligations: check::check_coroutine_obligations,
116        check_potentially_region_dependent_goals: check::check_potentially_region_dependent_goals,
117        check_type_wf: wfcheck::check_type_wf,
118        check_well_formed: wfcheck::check_well_formed,
119        ..*providers
120    };
121}
122
123fn adt_destructor(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<ty::Destructor> {
124    let dtor = tcx.calculate_dtor(def_id, always_applicable::check_drop_impl);
125    if dtor.is_none() && tcx.features().async_drop() {
126        if let Some(async_dtor) = adt_async_destructor(tcx, def_id) {
127            // When type has AsyncDrop impl, but doesn't have Drop impl, generate error
128            let span = tcx.def_span(async_dtor.impl_did);
129            tcx.dcx().emit_err(errors::AsyncDropWithoutSyncDrop { span });
130        }
131    }
132    dtor
133}
134
135fn adt_async_destructor(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<ty::AsyncDestructor> {
136    tcx.calculate_async_dtor(def_id, always_applicable::check_drop_impl)
137}
138
139/// Given a `DefId` for an opaque type in return position, find its parent item's return
140/// expressions.
141fn get_owner_return_paths(
142    tcx: TyCtxt<'_>,
143    def_id: LocalDefId,
144) -> Option<(LocalDefId, ReturnsVisitor<'_>)> {
145    let hir_id = tcx.local_def_id_to_hir_id(def_id);
146    let parent_id = tcx.hir_get_parent_item(hir_id).def_id;
147    tcx.hir_node_by_def_id(parent_id).body_id().map(|body_id| {
148        let body = tcx.hir_body(body_id);
149        let mut visitor = ReturnsVisitor::default();
150        visitor.visit_body(body);
151        (parent_id, visitor)
152    })
153}
154
155pub(super) fn maybe_check_static_with_link_section(tcx: TyCtxt<'_>, id: LocalDefId) {
156    // Only restricted on wasm target for now
157    if !tcx.sess.target.is_like_wasm {
158        return;
159    }
160
161    // If `#[link_section]` is missing, then nothing to verify
162    let Some(link_section) = tcx.codegen_fn_attrs(id).link_section else {
163        return;
164    };
165
166    // For the wasm32 target statics with `#[link_section]` other than `.init_array`
167    // are placed into custom sections of the final output file, but this isn't like
168    // custom sections of other executable formats. Namely we can only embed a list
169    // of bytes, nothing with provenance (pointers to anything else). If any
170    // provenance show up, reject it here.
171    // `#[link_section]` may contain arbitrary, or even undefined bytes, but it is
172    // the consumer's responsibility to ensure all bytes that have been read
173    // have defined values.
174    //
175    // The `.init_array` section is left to go through the normal custom section code path.
176    // When dealing with `.init_array` wasm-ld currently has several limitations. This manifests
177    // in workarounds in user-code.
178    //
179    //   * The linker fails to merge multiple items in a crate into the .init_array section.
180    //     To work around this, a single array can be used placing multiple items in the array.
181    //     #[link_section = ".init_array"]
182    //     static FOO: [unsafe extern "C" fn(); 2] = [ctor, ctor];
183    //   * Even symbols marked used get gc'd from dependant crates unless at least one symbol
184    //     in the crate is marked with an `#[export_name]`
185    //
186    //  Once `.init_array` support in wasm-ld is complete, the user code workarounds should
187    //  continue to work, but would no longer be necessary.
188
189    if let Ok(alloc) = tcx.eval_static_initializer(id.to_def_id())
190        && !alloc.inner().provenance().ptrs().is_empty()
191        && !link_section.as_str().starts_with(".init_array")
192    {
193        let msg = "statics with a custom `#[link_section]` must be a \
194                        simple list of bytes on the wasm target with no \
195                        extra levels of indirection such as references";
196        tcx.dcx().span_err(tcx.def_span(id), msg);
197    }
198}
199
200fn missing_items_err(
201    tcx: TyCtxt<'_>,
202    impl_def_id: LocalDefId,
203    missing_items: &[ty::AssocItem],
204    full_impl_span: Span,
205) {
206    let missing_items =
207        missing_items.iter().filter(|trait_item| !trait_item.is_impl_trait_in_trait());
208
209    let missing_items_msg = missing_items
210        .clone()
211        .map(|trait_item| trait_item.name().to_string())
212        .collect::<Vec<_>>()
213        .join("`, `");
214
215    let sugg_sp = if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(full_impl_span)
216        && snippet.ends_with("}")
217    {
218        // `Span` before impl block closing brace.
219        let hi = full_impl_span.hi() - BytePos(1);
220        // Point at the place right before the closing brace of the relevant `impl` to suggest
221        // adding the associated item at the end of its body.
222        full_impl_span.with_lo(hi).with_hi(hi)
223    } else {
224        full_impl_span.shrink_to_hi()
225    };
226
227    // Obtain the level of indentation ending in `sugg_sp`.
228    let padding = tcx.sess.source_map().indentation_before(sugg_sp).unwrap_or_else(String::new);
229    let (mut missing_trait_item, mut missing_trait_item_none, mut missing_trait_item_label) =
230        (Vec::new(), Vec::new(), Vec::new());
231
232    for &trait_item in missing_items {
233        let snippet = {
    let _guard =
        ::rustc_middle::ty::print::pretty::RtnModeHelper::with(RtnMode::ForSignature);
    suggestion_signature(tcx, trait_item,
        tcx.impl_trait_ref(impl_def_id).instantiate_identity())
}with_types_for_signature!(suggestion_signature(
234            tcx,
235            trait_item,
236            tcx.impl_trait_ref(impl_def_id).instantiate_identity(),
237        ));
238        let code = ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0}{1}\n{0}", padding, snippet))
    })format!("{padding}{snippet}\n{padding}");
239        if let Some(span) = tcx.hir_span_if_local(trait_item.def_id) {
240            missing_trait_item_label
241                .push(errors::MissingTraitItemLabel { span, item: trait_item.name() });
242            missing_trait_item.push(errors::MissingTraitItemSuggestion {
243                span: sugg_sp,
244                code,
245                snippet,
246            });
247        } else {
248            missing_trait_item_none.push(errors::MissingTraitItemSuggestionNone {
249                span: sugg_sp,
250                code,
251                snippet,
252            })
253        }
254    }
255
256    tcx.dcx().emit_err(errors::MissingTraitItem {
257        span: tcx.span_of_impl(impl_def_id.to_def_id()).unwrap(),
258        missing_items_msg,
259        missing_trait_item_label,
260        missing_trait_item,
261        missing_trait_item_none,
262    });
263}
264
265fn missing_items_must_implement_one_of_err(
266    tcx: TyCtxt<'_>,
267    impl_span: Span,
268    missing_items: &[Ident],
269    annotation_span: Option<Span>,
270) {
271    let missing_items_msg =
272        missing_items.iter().map(Ident::to_string).collect::<Vec<_>>().join("`, `");
273
274    tcx.dcx().emit_err(errors::MissingOneOfTraitItem {
275        span: impl_span,
276        note: annotation_span,
277        missing_items_msg,
278    });
279}
280
281fn default_body_is_unstable(
282    tcx: TyCtxt<'_>,
283    impl_span: Span,
284    item_did: DefId,
285    feature: Symbol,
286    reason: Option<Symbol>,
287    issue: Option<NonZero<u32>>,
288) {
289    let missing_item_name = tcx.item_ident(item_did);
290    let (mut some_note, mut none_note, mut reason_str) = (false, false, String::new());
291    match reason {
292        Some(r) => {
293            some_note = true;
294            reason_str = r.to_string();
295        }
296        None => none_note = true,
297    };
298
299    let mut err = tcx.dcx().create_err(errors::MissingTraitItemUnstable {
300        span: impl_span,
301        some_note,
302        none_note,
303        missing_item_name,
304        feature,
305        reason: reason_str,
306    });
307
308    let inject_span = item_did.is_local().then(|| tcx.crate_level_attribute_injection_span());
309    rustc_session::parse::add_feature_diagnostics_for_issue(
310        &mut err,
311        &tcx.sess,
312        feature,
313        rustc_feature::GateIssue::Library(issue),
314        false,
315        inject_span,
316    );
317
318    err.emit();
319}
320
321/// Re-sugar `ty::GenericPredicates` in a way suitable to be used in structured suggestions.
322fn bounds_from_generic_predicates<'tcx>(
323    tcx: TyCtxt<'tcx>,
324    predicates: impl IntoIterator<Item = (ty::Clause<'tcx>, Span)>,
325    assoc: ty::AssocItem,
326) -> (String, String) {
327    let mut types: FxIndexMap<Ty<'tcx>, Vec<DefId>> = FxIndexMap::default();
328    let mut regions: FxIndexMap<Region<'tcx>, Vec<Region<'tcx>>> = FxIndexMap::default();
329    let mut projections = ::alloc::vec::Vec::new()vec![];
330    for (predicate, _) in predicates {
331        {
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event compiler/rustc_hir_analysis/src/check/mod.rs:331",
                        "rustc_hir_analysis::check", ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("compiler/rustc_hir_analysis/src/check/mod.rs"),
                        ::tracing_core::__macro_support::Option::Some(331u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_hir_analysis::check"),
                        ::tracing_core::field::FieldSet::new(&["message"],
                            ::tracing_core::callsite::Identifier(&__CALLSITE)),
                        ::tracing::metadata::Kind::EVENT)
                };
            ::tracing::callsite::DefaultCallsite::new(&META)
        };
    let enabled =
        ::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::DEBUG <=
                    ::tracing::level_filters::LevelFilter::current() &&
            {
                let interest = __CALLSITE.interest();
                !interest.is_never() &&
                    ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                        interest)
            };
    if enabled {
        (|value_set: ::tracing::field::ValueSet|
                    {
                        let meta = __CALLSITE.metadata();
                        ::tracing::Event::dispatch(meta, &value_set);
                        ;
                    })({
                #[allow(unused_imports)]
                use ::tracing::field::{debug, display, Value};
                let mut iter = __CALLSITE.metadata().fields().iter();
                __CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                    ::tracing::__macro_support::Option::Some(&format_args!("predicate {0:?}",
                                                    predicate) as &dyn Value))])
            });
    } else { ; }
};debug!("predicate {:?}", predicate);
332        let bound_predicate = predicate.kind();
333        match bound_predicate.skip_binder() {
334            ty::ClauseKind::Trait(trait_predicate) => {
335                let entry = types.entry(trait_predicate.self_ty()).or_default();
336                let def_id = trait_predicate.def_id();
337                if !tcx.is_default_trait(def_id) && !tcx.is_lang_item(def_id, LangItem::Sized) {
338                    // Do not add that restriction to the list if it is a positive requirement.
339                    entry.push(trait_predicate.def_id());
340                }
341            }
342            ty::ClauseKind::Projection(projection_pred) => {
343                projections.push(bound_predicate.rebind(projection_pred));
344            }
345            ty::ClauseKind::RegionOutlives(OutlivesPredicate(a, b)) => {
346                regions.entry(a).or_default().push(b);
347            }
348            _ => {}
349        }
350    }
351
352    let mut where_clauses = ::alloc::vec::Vec::new()vec![];
353    let generics = tcx.generics_of(assoc.def_id);
354    let params = generics
355        .own_params
356        .iter()
357        .filter(|p| !p.kind.is_synthetic())
358        .map(|p| match tcx.mk_param_from_def(p).kind() {
359            ty::GenericArgKind::Type(ty) => {
360                let bounds =
361                    types.get(&ty).map(Cow::Borrowed).unwrap_or_else(|| Cow::Owned(Vec::new()));
362                let mut bounds_str = ::alloc::vec::Vec::new()vec![];
363                for bound in bounds.iter().copied() {
364                    let mut projections_str = ::alloc::vec::Vec::new()vec![];
365                    for projection in &projections {
366                        let p = projection.skip_binder();
367                        if bound == tcx.parent(p.projection_term.def_id)
368                            && p.projection_term.self_ty() == ty
369                        {
370                            let name = tcx.item_name(p.projection_term.def_id);
371                            projections_str.push(::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0} = {1}", name, p.term))
    })format!("{} = {}", name, p.term));
372                        }
373                    }
374                    let bound_def_path = if tcx.is_lang_item(bound, LangItem::MetaSized) {
375                        String::from("?Sized")
376                    } else {
377                        tcx.def_path_str(bound)
378                    };
379                    if projections_str.is_empty() {
380                        where_clauses.push(::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0}: {1}", ty, bound_def_path))
    })format!("{}: {}", ty, bound_def_path));
381                    } else {
382                        bounds_str.push(::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0}<{1}>", bound_def_path,
                projections_str.join(", ")))
    })format!(
383                            "{}<{}>",
384                            bound_def_path,
385                            projections_str.join(", ")
386                        ));
387                    }
388                }
389                if bounds_str.is_empty() {
390                    ty.to_string()
391                } else {
392                    ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0}: {1}", ty,
                bounds_str.join(" + ")))
    })format!("{}: {}", ty, bounds_str.join(" + "))
393                }
394            }
395            ty::GenericArgKind::Const(ct) => {
396                ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("const {1}: {0}",
                tcx.type_of(p.def_id).skip_binder(), ct))
    })format!("const {ct}: {}", tcx.type_of(p.def_id).skip_binder())
397            }
398            ty::GenericArgKind::Lifetime(region) => {
399                if let Some(v) = regions.get(&region)
400                    && !v.is_empty()
401                {
402                    ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{1}: {0}",
                v.into_iter().map(Region::to_string).collect::<Vec<_>>().join(" + "),
                region))
    })format!(
403                        "{region}: {}",
404                        v.into_iter().map(Region::to_string).collect::<Vec<_>>().join(" + ")
405                    )
406                } else {
407                    region.to_string()
408                }
409            }
410        })
411        .collect::<Vec<_>>();
412    for (ty, bounds) in types.into_iter() {
413        if !#[allow(non_exhaustive_omitted_patterns)] match ty.kind() {
    ty::Param(_) => true,
    _ => false,
}matches!(ty.kind(), ty::Param(_)) {
414            // Avoid suggesting the following:
415            // fn foo<T, <T as Trait>::Bar>(_: T) where T: Trait, <T as Trait>::Bar: Other {}
416            where_clauses.extend(
417                bounds.into_iter().map(|bound| ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0}: {1}", ty,
                tcx.def_path_str(bound)))
    })format!("{}: {}", ty, tcx.def_path_str(bound))),
418            );
419        }
420    }
421
422    let generics =
423        if params.is_empty() { "".to_string() } else { ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("<{0}>", params.join(", ")))
    })format!("<{}>", params.join(", ")) };
424
425    let where_clauses = if where_clauses.is_empty() {
426        "".to_string()
427    } else {
428        ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!(" where {0}",
                where_clauses.join(", ")))
    })format!(" where {}", where_clauses.join(", "))
429    };
430
431    (generics, where_clauses)
432}
433
434/// Return placeholder code for the given function.
435fn fn_sig_suggestion<'tcx>(
436    tcx: TyCtxt<'tcx>,
437    sig: ty::FnSig<'tcx>,
438    ident: Ident,
439    predicates: impl IntoIterator<Item = (ty::Clause<'tcx>, Span)>,
440    assoc: ty::AssocItem,
441) -> String {
442    let args = sig
443        .inputs()
444        .iter()
445        .enumerate()
446        .map(|(i, ty)| {
447            Some(match ty.kind() {
448                ty::Param(_) if assoc.is_method() && i == 0 => "self".to_string(),
449                ty::Ref(reg, ref_ty, mutability) if i == 0 => {
450                    let reg = ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0} ", reg))
    })format!("{reg} ");
451                    let reg = match &reg[..] {
452                        "'_ " | " " => "",
453                        reg => reg,
454                    };
455                    if assoc.is_method() {
456                        match ref_ty.kind() {
457                            ty::Param(param) if param.name == kw::SelfUpper => {
458                                ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("&{0}{1}self", reg,
                mutability.prefix_str()))
    })format!("&{}{}self", reg, mutability.prefix_str())
459                            }
460
461                            _ => ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("self: {0}", ty))
    })format!("self: {ty}"),
462                        }
463                    } else {
464                        ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("_: {0}", ty))
    })format!("_: {ty}")
465                    }
466                }
467                _ => {
468                    if assoc.is_method() && i == 0 {
469                        ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("self: {0}", ty))
    })format!("self: {ty}")
470                    } else {
471                        ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("_: {0}", ty))
    })format!("_: {ty}")
472                    }
473                }
474            })
475        })
476        .chain(std::iter::once(if sig.c_variadic { Some("...".to_string()) } else { None }))
477        .flatten()
478        .collect::<Vec<String>>()
479        .join(", ");
480    let mut output = sig.output();
481
482    let asyncness = if tcx.asyncness(assoc.def_id).is_async() {
483        output = if let ty::Alias(_, alias_ty) = *output.kind()
484            && let Some(output) = tcx
485                .explicit_item_self_bounds(alias_ty.def_id)
486                .iter_instantiated_copied(tcx, alias_ty.args)
487                .find_map(|(bound, _)| {
488                    bound.as_projection_clause()?.no_bound_vars()?.term.as_type()
489                }) {
490            output
491        } else {
492            ::rustc_middle::util::bug::span_bug_fmt(ident.span,
    format_args!("expected async fn to have `impl Future` output, but it returns {0}",
        output))span_bug!(
493                ident.span,
494                "expected async fn to have `impl Future` output, but it returns {output}"
495            )
496        };
497        "async "
498    } else {
499        ""
500    };
501
502    let output = if !output.is_unit() { ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!(" -> {0}", output))
    })format!(" -> {output}") } else { String::new() };
503
504    let safety = sig.safety.prefix_str();
505    let (generics, where_clauses) = bounds_from_generic_predicates(tcx, predicates, assoc);
506
507    // FIXME: this is not entirely correct, as the lifetimes from borrowed params will
508    // not be present in the `fn` definition, nor will we account for renamed
509    // lifetimes between the `impl` and the `trait`, but this should be good enough to
510    // fill in a significant portion of the missing code, and other subsequent
511    // suggestions can help the user fix the code.
512    ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0}{1}fn {2}{3}({4}){5}{6} {{ todo!() }}",
                safety, asyncness, ident, generics, args, output,
                where_clauses))
    })format!("{safety}{asyncness}fn {ident}{generics}({args}){output}{where_clauses} {{ todo!() }}")
513}
514
515/// Return placeholder code for the given associated item.
516/// Similar to `ty::AssocItem::suggestion`, but appropriate for use as the code snippet of a
517/// structured suggestion.
518fn suggestion_signature<'tcx>(
519    tcx: TyCtxt<'tcx>,
520    assoc: ty::AssocItem,
521    impl_trait_ref: ty::TraitRef<'tcx>,
522) -> String {
523    let args = ty::GenericArgs::identity_for_item(tcx, assoc.def_id).rebase_onto(
524        tcx,
525        assoc.container_id(tcx),
526        impl_trait_ref.with_replaced_self_ty(tcx, tcx.types.self_param).args,
527    );
528
529    match assoc.kind {
530        ty::AssocKind::Fn { .. } => fn_sig_suggestion(
531            tcx,
532            tcx.liberate_late_bound_regions(
533                assoc.def_id,
534                tcx.fn_sig(assoc.def_id).instantiate(tcx, args),
535            ),
536            assoc.ident(tcx),
537            tcx.predicates_of(assoc.def_id).instantiate_own(tcx, args),
538            assoc,
539        ),
540        ty::AssocKind::Type { .. } => {
541            let (generics, where_clauses) = bounds_from_generic_predicates(
542                tcx,
543                tcx.predicates_of(assoc.def_id).instantiate_own(tcx, args),
544                assoc,
545            );
546            ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("type {0}{1} = /* Type */{2};",
                assoc.name(), generics, where_clauses))
    })format!("type {}{generics} = /* Type */{where_clauses};", assoc.name())
547        }
548        ty::AssocKind::Const { name } => {
549            let ty = tcx.type_of(assoc.def_id).instantiate_identity();
550            let val = tcx
551                .infer_ctxt()
552                .build(TypingMode::non_body_analysis())
553                .err_ctxt()
554                .ty_kind_suggestion(tcx.param_env(assoc.def_id), ty)
555                .unwrap_or_else(|| "value".to_string());
556            ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("const {0}: {1} = {2};", name, ty,
                val))
    })format!("const {}: {} = {};", name, ty, val)
557        }
558    }
559}
560
561/// Emit an error when encountering two or more variants in a transparent enum.
562fn bad_variant_count<'tcx>(tcx: TyCtxt<'tcx>, adt: ty::AdtDef<'tcx>, sp: Span, did: DefId) {
563    let variant_spans: Vec<_> = adt
564        .variants()
565        .iter()
566        .map(|variant| tcx.hir_span_if_local(variant.def_id).unwrap())
567        .collect();
568    let (mut spans, mut many) = (Vec::new(), None);
569    if let [start @ .., end] = &*variant_spans {
570        spans = start.to_vec();
571        many = Some(*end);
572    }
573    tcx.dcx().emit_err(errors::TransparentEnumVariant {
574        span: sp,
575        spans,
576        many,
577        number: adt.variants().len(),
578        path: tcx.def_path_str(did),
579    });
580}
581
582/// Emit an error when encountering two or more non-zero-sized fields in a transparent
583/// enum.
584fn bad_non_zero_sized_fields<'tcx>(
585    tcx: TyCtxt<'tcx>,
586    adt: ty::AdtDef<'tcx>,
587    field_count: usize,
588    field_spans: impl Iterator<Item = Span>,
589    sp: Span,
590) {
591    if adt.is_enum() {
592        tcx.dcx().emit_err(errors::TransparentNonZeroSizedEnum {
593            span: sp,
594            spans: field_spans.collect(),
595            field_count,
596            desc: adt.descr(),
597        });
598    } else {
599        tcx.dcx().emit_err(errors::TransparentNonZeroSized {
600            span: sp,
601            spans: field_spans.collect(),
602            field_count,
603            desc: adt.descr(),
604        });
605    }
606}
607
608// FIXME: Consider moving this method to a more fitting place.
609pub fn potentially_plural_count(count: usize, word: &str) -> String {
610    ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0} {1}{2}", count, word,
                if count == 1 { "" } else { "s" }))
    })format!("{} {}{}", count, word, pluralize!(count))
611}
612
613pub fn check_function_signature<'tcx>(
614    tcx: TyCtxt<'tcx>,
615    mut cause: ObligationCause<'tcx>,
616    fn_id: DefId,
617    expected_sig: ty::PolyFnSig<'tcx>,
618) -> Result<(), ErrorGuaranteed> {
619    fn extract_span_for_error_reporting<'tcx>(
620        tcx: TyCtxt<'tcx>,
621        err: TypeError<'_>,
622        cause: &ObligationCause<'tcx>,
623        fn_id: LocalDefId,
624    ) -> rustc_span::Span {
625        let mut args = {
626            let node = tcx.expect_hir_owner_node(fn_id);
627            let decl = node.fn_decl().unwrap_or_else(|| ::rustc_middle::util::bug::bug_fmt(format_args!("expected fn decl, found {0:?}",
        node))bug!("expected fn decl, found {:?}", node));
628            decl.inputs.iter().map(|t| t.span).chain(std::iter::once(decl.output.span()))
629        };
630
631        match err {
632            TypeError::ArgumentMutability(i)
633            | TypeError::ArgumentSorts(ExpectedFound { .. }, i) => args.nth(i).unwrap(),
634            _ => cause.span,
635        }
636    }
637
638    let local_id = fn_id.as_local().unwrap_or(CRATE_DEF_ID);
639
640    let param_env = ty::ParamEnv::empty();
641
642    let infcx = &tcx.infer_ctxt().build(TypingMode::non_body_analysis());
643    let ocx = ObligationCtxt::new_with_diagnostics(infcx);
644
645    let actual_sig = tcx.fn_sig(fn_id).instantiate_identity();
646
647    let norm_cause = ObligationCause::misc(cause.span, local_id);
648    let actual_sig = ocx.normalize(&norm_cause, param_env, actual_sig);
649
650    match ocx.eq(&cause, param_env, expected_sig, actual_sig) {
651        Ok(()) => {
652            let errors = ocx.evaluate_obligations_error_on_ambiguity();
653            if !errors.is_empty() {
654                return Err(infcx.err_ctxt().report_fulfillment_errors(errors));
655            }
656        }
657        Err(err) => {
658            let err_ctxt = infcx.err_ctxt();
659            if fn_id.is_local() {
660                cause.span = extract_span_for_error_reporting(tcx, err, &cause, local_id);
661            }
662            let failure_code = cause.as_failure_code_diag(err, cause.span, ::alloc::vec::Vec::new()vec![]);
663            let mut diag = tcx.dcx().create_err(failure_code);
664            err_ctxt.note_type_err(
665                &mut diag,
666                &cause,
667                None,
668                Some(param_env.and(infer::ValuePairs::PolySigs(ExpectedFound {
669                    expected: expected_sig,
670                    found: actual_sig,
671                }))),
672                err,
673                false,
674                None,
675            );
676            return Err(diag.emit());
677        }
678    }
679
680    if let Err(e) = ocx.resolve_regions_and_report_errors(local_id, param_env, []) {
681        return Err(e);
682    }
683
684    Ok(())
685}