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