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