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::{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::errors::feature_err;
95use rustc_span::def_id::CRATE_DEF_ID;
96use rustc_span::{BytePos, DUMMY_SP, Ident, Span, Symbol, kw};
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, diagnostics};
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(diagnostics::AsyncDropWithoutSyncDrop { span });
130        }
131    }
132    dtor
133}
134
135fn adt_async_destructor(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<ty::AsyncDestructor> {
136    let result = tcx.calculate_async_dtor(def_id, always_applicable::check_drop_impl);
137    // Async drop in libstd/libcore would become insta-stable — catch that mistake.
138    if result.is_some() && tcx.features().staged_api() {
139        ::rustc_middle::util::bug::span_bug_fmt(tcx.def_span(def_id),
    format_args!("don\'t use async drop in libstd, it becomes insta-stable"));span_bug!(tcx.def_span(def_id), "don't use async drop in libstd, it becomes insta-stable");
140    }
141    result
142}
143
144/// Given a `DefId` for an opaque type in return position, find its parent item's return
145/// expressions.
146fn get_owner_return_paths(
147    tcx: TyCtxt<'_>,
148    def_id: LocalDefId,
149) -> Option<(LocalDefId, ReturnsVisitor<'_>)> {
150    let hir_id = tcx.local_def_id_to_hir_id(def_id);
151    let parent_id = tcx.hir_get_parent_item(hir_id).def_id;
152    tcx.hir_node_by_def_id(parent_id).body_id().map(|body_id| {
153        let body = tcx.hir_body(body_id);
154        let mut visitor = ReturnsVisitor::default();
155        visitor.visit_body(body);
156        (parent_id, visitor)
157    })
158}
159
160pub(super) fn maybe_check_static_with_link_section(tcx: TyCtxt<'_>, id: LocalDefId) {
161    // Only restricted on wasm target for now
162    if !tcx.sess.target.is_like_wasm {
163        return;
164    }
165
166    // If `#[link_section]` is missing, then nothing to verify
167    let Some(link_section) = tcx.codegen_fn_attrs(id).link_section else {
168        return;
169    };
170
171    // For the wasm32 target statics with `#[link_section]` other than `.init_array`
172    // are placed into custom sections of the final output file, but this isn't like
173    // custom sections of other executable formats. Namely we can only embed a list
174    // of bytes, nothing with provenance (pointers to anything else). If any
175    // provenance show up, reject it here.
176    // `#[link_section]` may contain arbitrary, or even undefined bytes, but it is
177    // the consumer's responsibility to ensure all bytes that have been read
178    // have defined values.
179    //
180    // The `.init_array` section is left to go through the normal custom section code path.
181    // When dealing with `.init_array` wasm-ld currently has several limitations. This manifests
182    // in workarounds in user-code.
183    //
184    //   * The linker fails to merge multiple items in a crate into the .init_array section.
185    //     To work around this, a single array can be used placing multiple items in the array.
186    //     #[link_section = ".init_array"]
187    //     static FOO: [unsafe extern "C" fn(); 2] = [ctor, ctor];
188    //   * Even symbols marked used get gc'd from dependant crates unless at least one symbol
189    //     in the crate is marked with an `#[export_name]`
190    //
191    //  Once `.init_array` support in wasm-ld is complete, the user code workarounds should
192    //  continue to work, but would no longer be necessary.
193
194    if let Ok(alloc) = tcx.eval_static_initializer(id.to_def_id())
195        && !alloc.inner().provenance().ptrs().is_empty()
196        && !link_section.as_str().starts_with(".init_array")
197    {
198        let msg = "statics with a custom `#[link_section]` must be a \
199                        simple list of bytes on the wasm target with no \
200                        extra levels of indirection such as references";
201        tcx.dcx().span_err(tcx.def_span(id), msg);
202    }
203}
204
205fn missing_items_err(
206    tcx: TyCtxt<'_>,
207    impl_def_id: LocalDefId,
208    missing_items: &[ty::AssocItem],
209    full_impl_span: Span,
210) {
211    let missing_items =
212        missing_items.iter().filter(|trait_item| !trait_item.is_impl_trait_in_trait());
213
214    let missing_items_msg = missing_items
215        .clone()
216        .map(|trait_item| trait_item.name().to_string())
217        .collect::<Vec<_>>()
218        .join("`, `");
219
220    let sugg_sp = if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(full_impl_span)
221        && snippet.ends_with("}")
222    {
223        // `Span` before impl block closing brace.
224        let hi = full_impl_span.hi() - BytePos(1);
225        // Point at the place right before the closing brace of the relevant `impl` to suggest
226        // adding the associated item at the end of its body.
227        full_impl_span.with_lo(hi).with_hi(hi)
228    } else {
229        full_impl_span.shrink_to_hi()
230    };
231
232    // Obtain the level of indentation ending in `sugg_sp`.
233    let padding = tcx.sess.source_map().indentation_before(sugg_sp).unwrap_or_else(String::new);
234    let (mut missing_trait_item, mut missing_trait_item_none, mut missing_trait_item_label) =
235        (Vec::new(), Vec::new(), Vec::new());
236
237    for &trait_item in missing_items {
238        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().skip_norm_wip())
}with_types_for_signature!(suggestion_signature(
239            tcx,
240            trait_item,
241            tcx.impl_trait_ref(impl_def_id).instantiate_identity().skip_norm_wip(),
242        ));
243        let code = ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0}{1}\n{0}", padding, snippet))
    })format!("{padding}{snippet}\n{padding}");
244        if let Some(span) = tcx.hir_span_if_local(trait_item.def_id) {
245            missing_trait_item_label
246                .push(diagnostics::MissingTraitItemLabel { span, item: trait_item.name() });
247            missing_trait_item.push(diagnostics::MissingTraitItemSuggestion {
248                span: sugg_sp,
249                code,
250                snippet,
251            });
252        } else {
253            missing_trait_item_none.push(diagnostics::MissingTraitItemSuggestionNone {
254                span: sugg_sp,
255                code,
256                snippet,
257            })
258        }
259    }
260
261    tcx.dcx().emit_err(diagnostics::MissingTraitItem {
262        span: tcx.span_of_impl(impl_def_id.to_def_id()).unwrap(),
263        missing_items_msg,
264        missing_trait_item_label,
265        missing_trait_item,
266        missing_trait_item_none,
267    });
268}
269
270fn missing_items_must_implement_one_of_err(
271    tcx: TyCtxt<'_>,
272    impl_span: Span,
273    missing_items: &[Ident],
274    annotation_span: Option<Span>,
275) {
276    let missing_items_msg =
277        missing_items.iter().map(Ident::to_string).collect::<Vec<_>>().join("`, `");
278
279    tcx.dcx().emit_err(diagnostics::MissingOneOfTraitItem {
280        span: impl_span,
281        note: annotation_span,
282        missing_items_msg,
283    });
284}
285
286fn default_body_is_unstable(
287    tcx: TyCtxt<'_>,
288    impl_span: Span,
289    item_did: DefId,
290    feature: Symbol,
291    reason: Option<Symbol>,
292    issue: Option<NonZero<u32>>,
293) {
294    let missing_item_name = tcx.item_ident(item_did);
295    let (mut some_note, mut none_note, mut reason_str) = (false, false, String::new());
296    match reason {
297        Some(r) => {
298            some_note = true;
299            reason_str = r.to_string();
300        }
301        None => none_note = true,
302    };
303
304    let mut err = tcx.dcx().create_err(diagnostics::MissingTraitItemUnstable {
305        span: impl_span,
306        some_note,
307        none_note,
308        missing_item_name,
309        feature,
310        reason: reason_str,
311    });
312
313    let inject_span = item_did.is_local().then(|| tcx.crate_level_attribute_injection_span());
314    rustc_session::errors::add_feature_diagnostics_for_issue(
315        &mut err,
316        &tcx.sess,
317        feature,
318        rustc_feature::GateIssue::Library(issue),
319        false,
320        inject_span,
321    );
322
323    err.emit();
324}
325
326/// Re-sugar `ty::GenericPredicates` in a way suitable to be used in structured suggestions.
327fn bounds_from_generic_predicates<'tcx>(
328    tcx: TyCtxt<'tcx>,
329    predicates: impl IntoIterator<Item = (ty::Clause<'tcx>, Span)>,
330    assoc: ty::AssocItem,
331) -> (String, String) {
332    let mut types: FxIndexMap<Ty<'tcx>, Vec<DefId>> = FxIndexMap::default();
333    let mut regions: FxIndexMap<Region<'tcx>, Vec<Region<'tcx>>> = FxIndexMap::default();
334    let mut projections = ::alloc::vec::Vec::new()vec![];
335    for (predicate, _) in predicates {
336        {
    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:336",
                        "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(336u32),
                        ::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);
337        let bound_predicate = predicate.kind();
338        match bound_predicate.skip_binder() {
339            ty::ClauseKind::Trait(trait_predicate) => {
340                let entry = types.entry(trait_predicate.self_ty()).or_default();
341                let def_id = trait_predicate.def_id();
342                if !tcx.is_default_trait(def_id) && !tcx.is_lang_item(def_id, LangItem::Sized) {
343                    // Do not add that restriction to the list if it is a positive requirement.
344                    entry.push(trait_predicate.def_id());
345                }
346            }
347            ty::ClauseKind::Projection(projection_pred) => {
348                projections.push(bound_predicate.rebind(projection_pred));
349            }
350            ty::ClauseKind::RegionOutlives(OutlivesPredicate(a, b)) => {
351                regions.entry(a).or_default().push(b);
352            }
353            _ => {}
354        }
355    }
356
357    let mut where_clauses = ::alloc::vec::Vec::new()vec![];
358    let generics = tcx.generics_of(assoc.def_id);
359    let params = generics
360        .own_params
361        .iter()
362        .filter(|p| !p.kind.is_synthetic())
363        .map(|p| match tcx.mk_param_from_def(p).kind() {
364            ty::GenericArgKind::Type(ty) => {
365                let bounds =
366                    types.get(&ty).map(Cow::Borrowed).unwrap_or_else(|| Cow::Owned(Vec::new()));
367                let mut bounds_str = ::alloc::vec::Vec::new()vec![];
368                for bound in bounds.iter().copied() {
369                    let mut projections_str = ::alloc::vec::Vec::new()vec![];
370                    for projection in &projections {
371                        let p = projection.skip_binder();
372                        if bound == p.projection_term.trait_def_id(tcx)
373                            && p.projection_term.self_ty() == ty
374                        {
375                            let name = tcx.item_name(p.projection_term.expect_projection_def_id());
376                            projections_str.push(::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0} = {1}", name, p.term))
    })format!("{} = {}", name, p.term));
377                        }
378                    }
379                    let bound_def_path = if tcx.is_lang_item(bound, LangItem::MetaSized) {
380                        String::from("?Sized")
381                    } else {
382                        tcx.def_path_str(bound)
383                    };
384                    if projections_str.is_empty() {
385                        where_clauses.push(::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0}: {1}", ty, bound_def_path))
    })format!("{}: {}", ty, bound_def_path));
386                    } else {
387                        bounds_str.push(::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0}<{1}>", bound_def_path,
                projections_str.join(", ")))
    })format!(
388                            "{}<{}>",
389                            bound_def_path,
390                            projections_str.join(", ")
391                        ));
392                    }
393                }
394                if bounds_str.is_empty() {
395                    ty.to_string()
396                } else {
397                    ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0}: {1}", ty,
                bounds_str.join(" + ")))
    })format!("{}: {}", ty, bounds_str.join(" + "))
398                }
399            }
400            ty::GenericArgKind::Const(ct) => {
401                ::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())
402            }
403            ty::GenericArgKind::Lifetime(region) => {
404                if let Some(v) = regions.get(&region)
405                    && !v.is_empty()
406                {
407                    ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{1}: {0}",
                v.into_iter().map(Region::to_string).collect::<Vec<_>>().join(" + "),
                region))
    })format!(
408                        "{region}: {}",
409                        v.into_iter().map(Region::to_string).collect::<Vec<_>>().join(" + ")
410                    )
411                } else {
412                    region.to_string()
413                }
414            }
415        })
416        .collect::<Vec<_>>();
417    for (ty, bounds) in types.into_iter() {
418        if !#[allow(non_exhaustive_omitted_patterns)] match ty.kind() {
    ty::Param(_) => true,
    _ => false,
}matches!(ty.kind(), ty::Param(_)) {
419            // Avoid suggesting the following:
420            // fn foo<T, <T as Trait>::Bar>(_: T) where T: Trait, <T as Trait>::Bar: Other {}
421            where_clauses.extend(
422                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))),
423            );
424        }
425    }
426
427    let generics =
428        if params.is_empty() { "".to_string() } else { ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("<{0}>", params.join(", ")))
    })format!("<{}>", params.join(", ")) };
429
430    let where_clauses = if where_clauses.is_empty() {
431        "".to_string()
432    } else {
433        ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!(" where {0}",
                where_clauses.join(", ")))
    })format!(" where {}", where_clauses.join(", "))
434    };
435
436    (generics, where_clauses)
437}
438
439/// Return placeholder code for the given function.
440fn fn_sig_suggestion<'tcx>(
441    tcx: TyCtxt<'tcx>,
442    sig: ty::FnSig<'tcx>,
443    ident: Ident,
444    predicates: impl IntoIterator<Item = (ty::Clause<'tcx>, Span)>,
445    assoc: ty::AssocItem,
446) -> String {
447    let splatted_arg_index = sig.splatted().map(usize::from);
448    let args = sig
449        .inputs()
450        .iter()
451        .enumerate()
452        .map(|(i, ty)| {
453            let splat = if splatted_arg_index == Some(i) { "#[splat] " } else { "" };
454            let arg_ty = match ty.kind() {
455                ty::Param(_) if assoc.is_method() && i == 0 => "self".to_string(),
456                ty::Ref(reg, ref_ty, mutability) if i == 0 => {
457                    let reg = ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0} ", reg))
    })format!("{reg} ");
458                    let reg = match &reg[..] {
459                        "'_ " | " " => "",
460                        reg => reg,
461                    };
462                    if assoc.is_method() {
463                        match ref_ty.kind() {
464                            ty::Param(param) if param.name == kw::SelfUpper => {
465                                ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("&{0}{1}self", reg,
                mutability.prefix_str()))
    })format!("&{}{}self", reg, mutability.prefix_str())
466                            }
467
468                            _ => ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("self: {0}", ty))
    })format!("self: {ty}"),
469                        }
470                    } else {
471                        ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("_: {0}", ty))
    })format!("_: {ty}")
472                    }
473                }
474                _ => {
475                    if assoc.is_method() && i == 0 {
476                        ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("self: {0}", ty))
    })format!("self: {ty}")
477                    } else {
478                        ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("_: {0}", ty))
    })format!("_: {ty}")
479                    }
480                }
481            };
482            Some(::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0}{1}", splat, arg_ty))
    })format!("{splat}{arg_ty}"))
483        })
484        .chain(std::iter::once(if sig.c_variadic() { Some("...".to_string()) } else { None }))
485        .flatten()
486        .collect::<Vec<String>>()
487        .join(", ");
488    let mut output = sig.output();
489
490    let asyncness = if tcx.asyncness(assoc.def_id).is_async() {
491        output = tcx.get_impl_future_output_ty(output).unwrap_or_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).skip_norm_wip(),
535            ),
536            assoc.ident(tcx),
537            tcx.predicates_of(assoc.def_id)
538                .instantiate_own(tcx, args)
539                .map(|(c, s)| (c.skip_norm_wip(), s)),
540            assoc,
541        ),
542        ty::AssocKind::Type { .. } => {
543            let (generics, where_clauses) = bounds_from_generic_predicates(
544                tcx,
545                tcx.predicates_of(assoc.def_id)
546                    .instantiate_own(tcx, args)
547                    .map(|(c, s)| (c.skip_norm_wip(), s)),
548                assoc,
549            );
550            ::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())
551        }
552        ty::AssocKind::Const { name, .. } => {
553            let ty = tcx.type_of(assoc.def_id).instantiate_identity().skip_norm_wip();
554            let val = tcx
555                .infer_ctxt()
556                .build(TypingMode::non_body_analysis())
557                .err_ctxt()
558                .ty_kind_suggestion(tcx.param_env(assoc.def_id), ty)
559                .unwrap_or_else(|| "value".to_string());
560            ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("const {0}: {1} = {2};", name, ty,
                val))
    })format!("const {}: {} = {};", name, ty, val)
561        }
562    }
563}
564
565/// Emit an error when encountering two or more variants in a transparent enum.
566fn bad_variant_count<'tcx>(tcx: TyCtxt<'tcx>, adt: ty::AdtDef<'tcx>, sp: Span, did: DefId) {
567    let variant_spans: Vec<_> = adt
568        .variants()
569        .iter()
570        .map(|variant| tcx.hir_span_if_local(variant.def_id).unwrap())
571        .collect();
572    let (mut spans, mut many) = (Vec::new(), None);
573    if let [start @ .., end] = &*variant_spans {
574        spans = start.to_vec();
575        many = Some(*end);
576    }
577    tcx.dcx().emit_err(diagnostics::TransparentEnumVariant {
578        span: sp,
579        spans,
580        many,
581        number: adt.variants().len(),
582        path: tcx.def_path_str(did),
583    });
584}
585
586// FIXME: Consider moving this method to a more fitting place.
587pub fn potentially_plural_count(count: usize, word: &str) -> String {
588    ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0} {1}{2}", count, word,
                if count == 1 { "" } else { "s" }))
    })format!("{} {}{}", count, word, pluralize!(count))
589}
590
591pub fn check_function_signature<'tcx>(
592    tcx: TyCtxt<'tcx>,
593    mut cause: ObligationCause<'tcx>,
594    fn_id: DefId,
595    expected_sig: ty::PolyFnSig<'tcx>,
596) -> Result<(), ErrorGuaranteed> {
597    fn extract_span_for_error_reporting<'tcx>(
598        tcx: TyCtxt<'tcx>,
599        err: TypeError<'_>,
600        cause: &ObligationCause<'tcx>,
601        fn_id: LocalDefId,
602    ) -> rustc_span::Span {
603        let mut args = {
604            let node = tcx.expect_hir_owner_node(fn_id);
605            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));
606            decl.inputs.iter().map(|t| t.span).chain(std::iter::once(decl.output.span()))
607        };
608
609        match err {
610            TypeError::ArgumentMutability(i)
611            | TypeError::ArgumentSorts(ExpectedFound { .. }, i) => args.nth(i).unwrap(),
612            _ => cause.span,
613        }
614    }
615
616    let local_id = fn_id.as_local().unwrap_or(CRATE_DEF_ID);
617
618    let param_env = ty::ParamEnv::empty();
619
620    let infcx = &tcx.infer_ctxt().build(TypingMode::non_body_analysis());
621    let ocx = ObligationCtxt::new_with_diagnostics(infcx);
622
623    let actual_sig = tcx.fn_sig(fn_id).instantiate_identity();
624
625    let norm_cause = ObligationCause::misc(cause.span, local_id);
626    let actual_sig = ocx.normalize(&norm_cause, param_env, actual_sig);
627
628    match ocx.eq(&cause, param_env, expected_sig, actual_sig) {
629        Ok(()) => {
630            let errors = ocx.evaluate_obligations_error_on_ambiguity();
631            if !errors.is_empty() {
632                return Err(infcx.err_ctxt().report_fulfillment_errors(errors));
633            }
634        }
635        Err(err) => {
636            let err_ctxt = infcx.err_ctxt();
637            if fn_id.is_local() {
638                cause.span = extract_span_for_error_reporting(tcx, err, &cause, local_id);
639            }
640            let failure_code = cause.as_failure_code_diag(err, cause.span, ::alloc::vec::Vec::new()vec![]);
641            let mut diag = tcx.dcx().create_err(failure_code);
642            err_ctxt.note_type_err(
643                &mut diag,
644                &cause,
645                None,
646                Some(param_env.and(infer::ValuePairs::PolySigs(ExpectedFound {
647                    expected: expected_sig,
648                    found: actual_sig,
649                }))),
650                err,
651                false,
652                None,
653            );
654            return Err(diag.emit());
655        }
656    }
657
658    if let Err(e) = ocx.resolve_regions_and_report_errors(local_id, param_env, []) {
659        return Err(e);
660    }
661
662    Ok(())
663}