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