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;
78use rustc_abi::VariantIdx;
79use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
80use rustc_errors::{ErrorGuaranteed, pluralize, struct_span_code_err};
81use rustc_hir::attrs::lang_items::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, TraitErrors};
87use rustc_middle::middle::stability::EvalResult;
88use rustc_middle::query::Providers;
89use rustc_middle::ty::error::{ExpectedFound, TypeError};
90use rustc_middle::ty::print::with_types_for_signature;
91use rustc_middle::ty::{
92    self, GenericArgs, GenericArgsRef, OutlivesClause, Region, Ty, TyCtxt, TypingMode,
93};
94use rustc_session::diagnostics::feature_err;
95use rustc_span::def_id::CRATE_DEF_ID;
96use rustc_span::{BytePos, DUMMY_SP, Ident, Span, Symbol, bug, kw, span_bug};
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::diagnostics::{
106    MissingTraitItemLabel, MissingTraitItemSuggestion, MissingTraitItemSuggestionNone,
107    MissingTraitItemSuggestionUnstable,
108};
109use crate::{check_c_variadic_abi, diagnostics};
110
111/// Adds query implementations to the [Providers] vtable, see [`rustc_middle::query`]
112pub(super) fn provide(providers: &mut Providers) {
113    *providers = Providers {
114        adt_destructor,
115        adt_async_destructor,
116        region_scope_tree,
117        collect_return_position_impl_trait_in_trait_tys,
118        compare_impl_item: compare_impl_item::compare_impl_item,
119        check_coroutine_obligations: check::check_coroutine_obligations,
120        check_potentially_region_dependent_goals: check::check_potentially_region_dependent_goals,
121        check_type_wf: wfcheck::check_type_wf,
122        check_well_formed: wfcheck::check_well_formed,
123        ..*providers
124    };
125}
126
127fn adt_destructor(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<ty::Destructor> {
128    let dtor = tcx.calculate_dtor(def_id, always_applicable::check_drop_impl);
129    if dtor.is_none() && tcx.features().async_drop() {
130        if let Some(async_dtor) = adt_async_destructor(tcx, def_id) {
131            // When type has AsyncDrop impl, but doesn't have Drop impl, generate error
132            let span = tcx.def_span(async_dtor.impl_did);
133            tcx.dcx().emit_err(diagnostics::AsyncDropWithoutSyncDrop { span });
134        }
135    }
136    dtor
137}
138
139fn adt_async_destructor(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<ty::AsyncDestructor> {
140    let result = tcx.calculate_async_dtor(def_id, always_applicable::check_drop_impl);
141    // Async drop in libstd/libcore would become insta-stable — catch that mistake.
142    if result.is_some() && tcx.features().staged_api() {
143        bug_impl(Some(tcx.def_span(def_id)),
    format_args!("don\'t use async drop in libstd, it becomes insta-stable"),
    Location::caller());span_bug!(tcx.def_span(def_id), "don't use async drop in libstd, it becomes insta-stable");
144    }
145    result
146}
147
148/// Given a `DefId` for an opaque type in return position, find its parent item's return
149/// expressions.
150fn get_owner_return_paths(
151    tcx: TyCtxt<'_>,
152    def_id: LocalDefId,
153) -> Option<(LocalDefId, ReturnsVisitor<'_>)> {
154    let hir_id = tcx.local_def_id_to_hir_id(def_id);
155    let parent_id = tcx.hir_get_parent_item(hir_id).def_id;
156    tcx.hir_node_by_def_id(parent_id).body_id().map(|body_id| {
157        let body = tcx.hir_body(body_id);
158        let mut visitor = ReturnsVisitor::default();
159        visitor.visit_body(body);
160        (parent_id, visitor)
161    })
162}
163
164pub(super) fn maybe_check_static_with_link_section(tcx: TyCtxt<'_>, id: LocalDefId) {
165    // Only restricted on wasm target for now
166    if !tcx.sess.target.is_like_wasm {
167        return;
168    }
169
170    // If `#[link_section]` is missing, then nothing to verify
171    let Some(link_section) = tcx.codegen_fn_attrs(id).link_section else {
172        return;
173    };
174
175    // For the wasm32 target statics with `#[link_section]` other than `.init_array`
176    // are placed into custom sections of the final output file, but this isn't like
177    // custom sections of other executable formats. Namely we can only embed a list
178    // of bytes, nothing with provenance (pointers to anything else). If any
179    // provenance show up, reject it here.
180    // `#[link_section]` may contain arbitrary, or even undefined bytes, but it is
181    // the consumer's responsibility to ensure all bytes that have been read
182    // have defined values.
183    //
184    // The `.init_array` section is left to go through the normal custom section code path.
185    // When dealing with `.init_array` wasm-ld currently has several limitations. This manifests
186    // in workarounds in user-code.
187    //
188    //   * The linker fails to merge multiple items in a crate into the .init_array section.
189    //     To work around this, a single array can be used placing multiple items in the array.
190    //     #[link_section = ".init_array"]
191    //     static FOO: [unsafe extern "C" fn(); 2] = [ctor, ctor];
192    //   * Even symbols marked used get gc'd from dependant crates unless at least one symbol
193    //     in the crate is marked with an `#[export_name]`
194    //
195    //  Once `.init_array` support in wasm-ld is complete, the user code workarounds should
196    //  continue to work, but would no longer be necessary.
197
198    if let Ok(alloc) = tcx.eval_static_initializer(id.to_def_id())
199        && !alloc.inner().provenance().ptrs().is_empty()
200        && !link_section.as_str().starts_with(".init_array")
201    {
202        let msg = "statics with a custom `#[link_section]` must be a \
203                        simple list of bytes on the wasm target with no \
204                        extra levels of indirection such as references";
205        tcx.dcx().span_err(tcx.def_span(id), msg);
206    }
207}
208
209fn impl_suggestion_span(tcx: TyCtxt<'_>, impl_def_id: LocalDefId) -> Span {
210    let full_impl_span = tcx.hir_span_with_body(tcx.local_def_id_to_hir_id(impl_def_id));
211    if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(full_impl_span)
212        && snippet.ends_with("}")
213    {
214        // `Span` before impl block closing brace.
215        let hi = full_impl_span.hi() - BytePos(1);
216        // Point at the place right before the closing brace of the relevant `impl` to suggest
217        // adding the associated item at the end of its body.
218        full_impl_span.with_lo(hi).with_hi(hi)
219    } else {
220        full_impl_span.shrink_to_hi()
221    }
222}
223
224fn missing_items_suggestions(
225    tcx: TyCtxt<'_>,
226    impl_def_id: LocalDefId,
227    missing_items: &[ty::AssocItem],
228) -> (
229    String,
230    Vec<MissingTraitItemSuggestion>,
231    Vec<MissingTraitItemSuggestionNone>,
232    Vec<MissingTraitItemSuggestionUnstable>,
233    Vec<MissingTraitItemLabel>,
234) {
235    let missing_items =
236        missing_items.iter().filter(|trait_item| !trait_item.is_impl_trait_in_trait());
237
238    let missing_items_msg = missing_items
239        .clone()
240        .map(|trait_item| trait_item.name().to_string())
241        .collect::<Vec<_>>()
242        .join("`, `");
243
244    let sugg_sp = impl_suggestion_span(tcx, impl_def_id);
245
246    // Obtain the level of indentation ending in `sugg_sp`.
247    let padding = tcx.sess.source_map().indentation_before(sugg_sp).unwrap_or_else(String::new);
248    let (
249        mut missing_trait_item,
250        mut missing_trait_item_none,
251        mut missing_trait_item_unstable,
252        mut missing_trait_item_label,
253    ) = (Vec::new(), Vec::new(), Vec::new(), Vec::new());
254
255    for &trait_item in missing_items {
256        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(
257            tcx,
258            trait_item,
259            tcx.impl_trait_ref(impl_def_id).instantiate_identity().skip_norm_wip(),
260        ));
261        let code = ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0}{1}\n{0}", padding, snippet))
    })format!("{padding}{snippet}\n{padding}");
262        if let Some(span) = tcx.hir_span_if_local(trait_item.def_id) {
263            missing_trait_item_label
264                .push(diagnostics::MissingTraitItemLabel { span, item: trait_item.name() });
265            missing_trait_item.push(diagnostics::MissingTraitItemSuggestion {
266                span: sugg_sp,
267                code,
268                snippet,
269            });
270        } else {
271            if let EvalResult::Deny { feature, .. } =
272                tcx.eval_stability(trait_item.def_id, None, sugg_sp, None)
273            {
274                missing_trait_item_unstable.push(diagnostics::MissingTraitItemSuggestionUnstable {
275                    span: sugg_sp,
276                    code,
277                    snippet,
278                    feature,
279                });
280            } else {
281                missing_trait_item_none.push(diagnostics::MissingTraitItemSuggestionNone {
282                    span: sugg_sp,
283                    code,
284                    snippet,
285                });
286            }
287        }
288    }
289
290    (
291        missing_items_msg,
292        missing_trait_item,
293        missing_trait_item_none,
294        missing_trait_item_unstable,
295        missing_trait_item_label,
296    )
297}
298
299fn missing_items_err(tcx: TyCtxt<'_>, impl_def_id: LocalDefId, missing_items: &[ty::AssocItem]) {
300    let (
301        missing_items_msg,
302        missing_trait_item,
303        missing_trait_item_none,
304        missing_trait_item_unstable,
305        missing_trait_item_label,
306    ) = missing_items_suggestions(tcx, impl_def_id, missing_items);
307
308    tcx.dcx().emit_err(diagnostics::MissingTraitItem {
309        span: tcx.span_of_impl(impl_def_id.to_def_id()).unwrap(),
310        missing_items_msg,
311        missing_trait_item_label,
312        missing_trait_item,
313        missing_trait_item_none,
314        missing_trait_item_unstable,
315    });
316}
317
318fn missing_items_must_implement_one_of_err(
319    tcx: TyCtxt<'_>,
320    impl_def_id: LocalDefId,
321    missing_items: impl Iterator<Item = Symbol>,
322    annotation_span: Option<Span>,
323) -> ErrorGuaranteed {
324    // Look up the associated items so we can use them to emit better errors.
325    let trait_def_id = tcx.impl_trait_id(impl_def_id);
326    let assoc_items = tcx.associated_items(trait_def_id);
327    let missing_items = missing_items
328        .flat_map(|s| assoc_items.filter_by_name_unhygienic_and_kind(s, ty::AssocTag::Fn))
329        .cloned()
330        .collect::<Vec<_>>();
331
332    let (
333        missing_items_msg,
334        missing_trait_item,
335        missing_trait_item_none,
336        missing_trait_item_unstable,
337        missing_trait_item_label,
338    ) = missing_items_suggestions(tcx, impl_def_id, &missing_items);
339
340    tcx.dcx().emit_err(diagnostics::MissingOneOfTraitItem {
341        span: tcx.def_span(impl_def_id),
342        note: annotation_span,
343        missing_items_msg,
344        missing_trait_item_label,
345        missing_trait_item,
346        missing_trait_item_unstable,
347        missing_trait_item_none,
348    })
349}
350
351fn default_body_is_unstable(
352    tcx: TyCtxt<'_>,
353    impl_span: Span,
354    item_did: DefId,
355    feature: Symbol,
356    reason: Option<Symbol>,
357    issue: Option<NonZero<u32>>,
358) {
359    let missing_item_name = tcx.item_ident(item_did);
360    let (mut some_note, mut none_note, mut reason_str) = (false, false, String::new());
361    match reason {
362        Some(r) => {
363            some_note = true;
364            reason_str = r.to_string();
365        }
366        None => none_note = true,
367    };
368
369    let mut err = tcx.dcx().create_err(diagnostics::MissingTraitItemUnstable {
370        span: impl_span,
371        some_note,
372        none_note,
373        missing_item_name,
374        feature,
375        reason: reason_str,
376    });
377
378    let inject_span = item_did.is_local().then(|| tcx.crate_level_attribute_injection_span());
379    rustc_session::diagnostics::add_feature_diagnostics_for_issue(
380        &mut err,
381        &tcx.sess,
382        feature,
383        rustc_feature::GateIssue::Library(issue),
384        false,
385        inject_span,
386    );
387
388    err.emit();
389}
390
391/// Re-sugar `ty::GenericClauses` in a way suitable to be used in structured suggestions.
392fn bounds_from_generic_clauses<'tcx>(
393    tcx: TyCtxt<'tcx>,
394    clauses: impl IntoIterator<Item = (ty::Clause<'tcx>, Span)>,
395    assoc: ty::AssocItem,
396) -> (String, String) {
397    let mut types: FxIndexMap<Ty<'tcx>, Vec<DefId>> = FxIndexMap::default();
398    let mut regions: FxIndexMap<Region<'tcx>, Vec<Region<'tcx>>> = FxIndexMap::default();
399    let mut projections = ::alloc::vec::Vec::new()vec![];
400    for (clause, _) in clauses {
401        {
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event /rustc-dev/923c95cdf5ba65cea505aa2ea829f578e1506ed8/compiler/rustc_hir_analysis/src/check/mod.rs:401",
                        "rustc_hir_analysis::check", ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("/rustc-dev/923c95cdf5ba65cea505aa2ea829f578e1506ed8/compiler/rustc_hir_analysis/src/check/mod.rs"),
                        ::tracing_core::__macro_support::Option::Some(401u32),
                        ::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};
                __CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&format_args!("clause {0:?}",
                                                    clause) as &dyn ::tracing::field::Value))])
            });
    } else { ; }
};debug!("clause {:?}", clause);
402        let bound_clause = clause.kind();
403        match bound_clause.skip_binder() {
404            ty::ClauseKind::Trait(trait_predicate) => {
405                let entry = types.entry(trait_predicate.self_ty()).or_default();
406                let def_id = trait_predicate.def_id();
407                if !tcx.is_default_trait(def_id) && !tcx.is_lang_item(def_id, LangItem::Sized) {
408                    // Do not add that restriction to the list if it is a positive requirement.
409                    entry.push(trait_predicate.def_id());
410                }
411            }
412            ty::ClauseKind::Projection(projection_pred) => {
413                projections.push(bound_clause.rebind(projection_pred));
414            }
415            ty::ClauseKind::RegionOutlives(OutlivesClause(a, b)) => {
416                regions.entry(a).or_default().push(b);
417            }
418            _ => {}
419        }
420    }
421
422    let mut where_clauses = ::alloc::vec::Vec::new()vec![];
423    let generics = tcx.generics_of(assoc.def_id);
424    let params = generics
425        .own_params
426        .iter()
427        .filter(|p| !p.kind.is_synthetic())
428        .map(|p| match tcx.mk_param_from_def(p).kind() {
429            ty::GenericArgKind::Type(ty) => {
430                let bounds =
431                    types.get(&ty).map(Cow::Borrowed).unwrap_or_else(|| Cow::Owned(Vec::new()));
432                let mut bounds_str = ::alloc::vec::Vec::new()vec![];
433                for bound in bounds.iter().copied() {
434                    let mut projections_str = ::alloc::vec::Vec::new()vec![];
435                    for projection in &projections {
436                        let p = projection.skip_binder();
437                        if bound == p.projection_term.trait_def_id(tcx)
438                            && p.projection_term.self_ty() == ty
439                        {
440                            let name = tcx.item_name(p.projection_term.expect_projection_def_id());
441                            projections_str.push(::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0} = {1}", name, p.term))
    })format!("{} = {}", name, p.term));
442                        }
443                    }
444                    let bound_def_path = if tcx.is_lang_item(bound, LangItem::MetaSized) {
445                        String::from("?Sized")
446                    } else {
447                        tcx.def_path_str(bound)
448                    };
449                    if projections_str.is_empty() {
450                        where_clauses.push(::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0}: {1}", ty, bound_def_path))
    })format!("{}: {}", ty, bound_def_path));
451                    } else {
452                        bounds_str.push(::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0}<{1}>", bound_def_path,
                projections_str.join(", ")))
    })format!(
453                            "{}<{}>",
454                            bound_def_path,
455                            projections_str.join(", ")
456                        ));
457                    }
458                }
459                if bounds_str.is_empty() {
460                    ty.to_string()
461                } else {
462                    ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0}: {1}", ty,
                bounds_str.join(" + ")))
    })format!("{}: {}", ty, bounds_str.join(" + "))
463                }
464            }
465            ty::GenericArgKind::Const(ct) => {
466                ::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())
467            }
468            ty::GenericArgKind::Lifetime(region) => {
469                if let Some(v) = regions.get(&region)
470                    && !v.is_empty()
471                {
472                    ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{1}: {0}",
                v.into_iter().map(Region::to_string).collect::<Vec<_>>().join(" + "),
                region))
    })format!(
473                        "{region}: {}",
474                        v.into_iter().map(Region::to_string).collect::<Vec<_>>().join(" + ")
475                    )
476                } else {
477                    region.to_string()
478                }
479            }
480        })
481        .collect::<Vec<_>>();
482    for (ty, bounds) in types.into_iter() {
483        if !#[allow(non_exhaustive_omitted_patterns)] match ty.kind() {
    ty::Param(_) => true,
    _ => false,
}matches!(ty.kind(), ty::Param(_)) {
484            // Avoid suggesting the following:
485            // fn foo<T, <T as Trait>::Bar>(_: T) where T: Trait, <T as Trait>::Bar: Other {}
486            where_clauses.extend(
487                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))),
488            );
489        }
490    }
491
492    let generics =
493        if params.is_empty() { "".to_string() } else { ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("<{0}>", params.join(", ")))
    })format!("<{}>", params.join(", ")) };
494
495    let where_clauses = if where_clauses.is_empty() {
496        "".to_string()
497    } else {
498        ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!(" where {0}",
                where_clauses.join(", ")))
    })format!(" where {}", where_clauses.join(", "))
499    };
500
501    (generics, where_clauses)
502}
503
504/// Return placeholder code for the given function.
505fn fn_sig_suggestion<'tcx>(
506    tcx: TyCtxt<'tcx>,
507    sig: ty::FnSig<'tcx>,
508    ident: Ident,
509    clauses: impl IntoIterator<Item = (ty::Clause<'tcx>, Span)>,
510    assoc: ty::AssocItem,
511) -> String {
512    let splatted_arg_index = sig.splatted().map(usize::from);
513    let args = sig
514        .inputs()
515        .iter()
516        .enumerate()
517        .map(|(i, ty)| {
518            let splat = if splatted_arg_index == Some(i) { "#[rustc_splat] " } else { "" };
519            let arg_ty = match ty.kind() {
520                ty::Param(_) if assoc.is_method() && i == 0 => "self".to_string(),
521                ty::Ref(reg, ref_ty, mutability) if i == 0 => {
522                    let reg = ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0} ", reg))
    })format!("{reg} ");
523                    let reg = match &reg[..] {
524                        "'_ " | " " => "",
525                        reg => reg,
526                    };
527                    if assoc.is_method() {
528                        match ref_ty.kind() {
529                            ty::Param(param) if param.name == kw::SelfUpper => {
530                                ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("&{0}{1}self", reg,
                mutability.prefix_str()))
    })format!("&{}{}self", reg, mutability.prefix_str())
531                            }
532
533                            _ => ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("self: {0}", ty))
    })format!("self: {ty}"),
534                        }
535                    } else {
536                        ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("_: {0}", ty))
    })format!("_: {ty}")
537                    }
538                }
539                _ => {
540                    if assoc.is_method() && i == 0 {
541                        ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("self: {0}", ty))
    })format!("self: {ty}")
542                    } else {
543                        ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("_: {0}", ty))
    })format!("_: {ty}")
544                    }
545                }
546            };
547            ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0}{1}", splat, arg_ty))
    })format!("{splat}{arg_ty}")
548        })
549        .chain(if sig.c_variadic() { Some("...".to_string()) } else { None })
550        .collect::<Vec<String>>()
551        .join(", ");
552    let mut output = sig.output();
553
554    let asyncness = if tcx.asyncness(assoc.def_id).is_async() {
555        output = tcx.get_impl_future_output_ty(output).unwrap_or_else(|| {
556            bug_impl(Some(ident.span),
    format_args!("expected async fn to have `impl Future` output, but it returns {0}",
        output), Location::caller())span_bug!(
557                ident.span,
558                "expected async fn to have `impl Future` output, but it returns {output}"
559            )
560        });
561        "async "
562    } else {
563        ""
564    };
565
566    let output = if !output.is_unit() { ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!(" -> {0}", output))
    })format!(" -> {output}") } else { String::new() };
567
568    let safety = sig.safety().prefix_str();
569    let (generics, where_clauses) = bounds_from_generic_clauses(tcx, clauses, assoc);
570
571    // FIXME: this is not entirely correct, as the lifetimes from borrowed params will
572    // not be present in the `fn` definition, nor will we account for renamed
573    // lifetimes between the `impl` and the `trait`, but this should be good enough to
574    // fill in a significant portion of the missing code, and other subsequent
575    // suggestions can help the user fix the code.
576    // ignore-tidy-todo
577    ::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!() }}")
578}
579
580/// Return placeholder code for the given associated item.
581/// Similar to `ty::AssocItem::suggestion`, but appropriate for use as the code snippet of a
582/// structured suggestion.
583fn suggestion_signature<'tcx>(
584    tcx: TyCtxt<'tcx>,
585    assoc: ty::AssocItem,
586    impl_trait_ref: ty::TraitRef<'tcx>,
587) -> String {
588    let args = ty::GenericArgs::identity_for_item(tcx, assoc.def_id).rebase_onto(
589        tcx,
590        assoc.container_id(tcx),
591        impl_trait_ref.with_replaced_self_ty(tcx, tcx.types.self_param).args,
592    );
593
594    match assoc.kind {
595        ty::AssocKind::Fn { .. } => fn_sig_suggestion(
596            tcx,
597            tcx.liberate_late_bound_regions(
598                assoc.def_id,
599                tcx.fn_sig(assoc.def_id).instantiate(tcx, args).skip_norm_wip(),
600            ),
601            assoc.ident(tcx),
602            tcx.clauses_of(assoc.def_id)
603                .instantiate_own(tcx, args)
604                .map(|(c, s)| (c.skip_norm_wip(), s)),
605            assoc,
606        ),
607        ty::AssocKind::Type { .. } => {
608            let (generics, where_clauses) = bounds_from_generic_clauses(
609                tcx,
610                tcx.clauses_of(assoc.def_id)
611                    .instantiate_own(tcx, args)
612                    .map(|(c, s)| (c.skip_norm_wip(), s)),
613                assoc,
614            );
615            ::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())
616        }
617        ty::AssocKind::Const { name, .. } => {
618            let ty = tcx.type_of(assoc.def_id).instantiate_identity().skip_norm_wip();
619            let val = tcx
620                .infer_ctxt()
621                .build(TypingMode::non_body_analysis())
622                .err_ctxt()
623                .ty_kind_suggestion(tcx.param_env(assoc.def_id), ty)
624                .unwrap_or_else(|| "value".to_string());
625            ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("const {0}: {1} = {2};", name, ty,
                val))
    })format!("const {}: {} = {};", name, ty, val)
626        }
627    }
628}
629
630/// Emit an error when encountering two or more variants in a transparent enum.
631fn bad_variant_count<'tcx>(tcx: TyCtxt<'tcx>, adt: ty::AdtDef<'tcx>, sp: Span, did: DefId) {
632    let variant_spans: Vec<_> = adt
633        .variants()
634        .iter()
635        .map(|variant| tcx.hir_span_if_local(variant.def_id).unwrap())
636        .collect();
637    let (mut spans, mut many) = (Vec::new(), None);
638    if let [start @ .., end] = &*variant_spans {
639        spans = start.to_vec();
640        many = Some(*end);
641    }
642    tcx.dcx().emit_err(diagnostics::TransparentEnumVariant {
643        span: sp,
644        spans,
645        many,
646        number: adt.variants().len(),
647        path: tcx.def_path_str(did),
648    });
649}
650
651// FIXME: Consider moving this method to a more fitting place.
652pub fn potentially_plural_count(count: usize, word: &str) -> String {
653    ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0} {1}{2}", count, word,
                if count == 1 { "" } else { "s" }))
    })format!("{} {}{}", count, word, pluralize!(count))
654}
655
656pub fn check_function_signature<'tcx>(
657    tcx: TyCtxt<'tcx>,
658    mut cause: ObligationCause<'tcx>,
659    fn_id: DefId,
660    expected_sig: ty::PolyFnSig<'tcx>,
661) -> Result<(), ErrorGuaranteed> {
662    fn extract_span_for_error_reporting<'tcx>(
663        tcx: TyCtxt<'tcx>,
664        err: TypeError<'_>,
665        cause: &ObligationCause<'tcx>,
666        fn_id: LocalDefId,
667    ) -> rustc_span::Span {
668        let mut args = {
669            let node = tcx.expect_hir_owner_node(fn_id);
670            let decl = node.fn_decl().unwrap_or_else(|| bug_impl(None, format_args!("expected fn decl, found {0:?}", node),
    Location::caller())bug!("expected fn decl, found {:?}", node));
671            decl.inputs.iter().map(|t| t.span).chain(std::iter::once(decl.output.span()))
672        };
673
674        match err {
675            TypeError::ArgumentMutability(i)
676            | TypeError::ArgumentSorts(ExpectedFound { .. }, i) => args.nth(i).unwrap(),
677            _ => cause.span,
678        }
679    }
680
681    let local_id = fn_id.as_local().unwrap_or(CRATE_DEF_ID);
682
683    let param_env = ty::ParamEnv::empty();
684
685    let infcx = &tcx.infer_ctxt().build(TypingMode::non_body_analysis());
686    let ocx = ObligationCtxt::new_with_diagnostics(infcx);
687
688    let actual_sig = tcx.fn_sig(fn_id).instantiate_identity();
689
690    let norm_cause = ObligationCause::misc(cause.span, local_id);
691    let actual_sig = ocx.normalize(&norm_cause, param_env, actual_sig);
692
693    match ocx.eq(&cause, param_env, expected_sig, actual_sig) {
694        Ok(()) => {
695            let errors = ocx.evaluate_obligations_error_on_ambiguity();
696            if let TraitErrors::HasErrors(errors) = errors {
697                return Err(infcx.err_ctxt().report_fulfillment_errors(errors));
698            }
699        }
700        Err(err) => {
701            let err_ctxt = infcx.err_ctxt();
702            if fn_id.is_local() {
703                cause.span = extract_span_for_error_reporting(tcx, err, &cause, local_id);
704            }
705            let failure_code = cause.as_failure_code_diag(err, cause.span, ::alloc::vec::Vec::new()vec![]);
706            let mut diag = tcx.dcx().create_err(failure_code);
707            err_ctxt.note_type_err(
708                &mut diag,
709                &cause,
710                None,
711                Some(param_env.and(infer::ValuePairs::PolySigs(ExpectedFound {
712                    expected: expected_sig,
713                    found: actual_sig,
714                }))),
715                err,
716                false,
717                None,
718            );
719            return Err(diag.emit());
720        }
721    }
722
723    if let Err(e) = ocx.resolve_regions_and_report_errors(local_id, param_env, []) {
724        return Err(e);
725    }
726
727    Ok(())
728}