Skip to main content

rustc_hir_analysis/check/
mod.rs

1/*!
2
3# typeck: check phase
4
5Within the check phase of type check, we check each item one at a time
6(bodies of function expressions are checked as part of the containing
7function). Inference is used to supply types wherever they are unknown.
8
9By far the most complex case is checking the body of a function. This
10can be broken down into several distinct phases:
11
12- gather: creates type variables to represent the type of each local
13  variable and pattern binding.
14
15- main: the main pass does the lion's share of the work: it
16  determines the types of all expressions, resolves
17  methods, checks for most invalid conditions, and so forth. In
18  some cases, where a type is unknown, it may create a type or region
19  variable and use that as the type of an expression.
20
21  In the process of checking, various constraints will be placed on
22  these type variables through the subtyping relationships requested
23  through the `demand` module. The `infer` module is in charge
24  of resolving those constraints.
25
26- regionck: after main is complete, the regionck pass goes over all
27  types looking for regions and making sure that they did not escape
28  into places where they are not in scope. This may also influence the
29  final assignments of the various region variables if there is some
30  flexibility.
31
32- writeback: writes the final types within a function body, replacing
33  type variables with their final inferred types. These final types
34  are written into the `tcx.node_types` table, which should *never* contain
35  any reference to a type variable.
36
37## Intermediate types
38
39While type checking a function, the intermediate types for the
40expressions, blocks, and so forth contained within the function are
41stored in `fcx.node_types` and `fcx.node_args`. These types
42may contain unresolved type variables. After type checking is
43complete, the functions in the writeback module are used to take the
44types from this table, resolve them, and then write them into their
45permanent home in the type context `tcx`.
46
47This means that during inferencing you should use `fcx.write_ty()`
48and `fcx.expr_ty()` / `fcx.node_ty()` to write/obtain the types of
49nodes within the function.
50
51The types of top-level items, which never contain unbound type
52variables, are stored directly into the `tcx` typeck_results.
53
54N.B., a type variable is not the same thing as a type parameter. A
55type variable is an instance of a type parameter. That is,
56given a generic function `fn foo<T>(t: T)`, while checking the
57function `foo`, the type `ty_param(0)` refers to the type `T`, which
58is treated in abstract. However, when `foo()` is called, `T` will be
59instantiated with a fresh type variable `N`. This variable will
60eventually be resolved to some concrete type (which might itself be
61a type parameter).
62
63*/
64
65pub mod always_applicable;
66mod check;
67mod compare_eii;
68mod compare_impl_item;
69mod entry;
70pub mod intrinsic;
71mod region;
72pub mod wfcheck;
73
74use std::borrow::Cow;
75use std::num::NonZero;
76
77pub use check::{check_abi, check_custom_abi};
78use rustc_abi::VariantIdx;
79use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
80use rustc_errors::{ErrorGuaranteed, pluralize, struct_span_code_err};
81use rustc_hir::LangItem;
82use rustc_hir::def_id::{DefId, LocalDefId};
83use rustc_hir::intravisit::Visitor;
84use rustc_index::bit_set::DenseBitSet;
85use rustc_infer::infer::{self, TyCtxtInferExt as _};
86use rustc_infer::traits::ObligationCause;
87use rustc_middle::query::Providers;
88use rustc_middle::ty::error::{ExpectedFound, TypeError};
89use rustc_middle::ty::print::with_types_for_signature;
90use rustc_middle::ty::{
91    self, GenericArgs, GenericArgsRef, OutlivesPredicate, Region, Ty, TyCtxt, TypingMode,
92    Unnormalized,
93};
94use rustc_middle::{bug, span_bug};
95use rustc_session::errors::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::{check_c_variadic_abi, diagnostics};
107
108/// Adds query implementations to the [Providers] vtable, see [`rustc_middle::query`]
109pub(super) fn provide(providers: &mut Providers) {
110    *providers = Providers {
111        adt_destructor,
112        adt_async_destructor,
113        region_scope_tree,
114        collect_return_position_impl_trait_in_trait_tys,
115        compare_impl_item: compare_impl_item::compare_impl_item,
116        check_coroutine_obligations: check::check_coroutine_obligations,
117        check_potentially_region_dependent_goals: check::check_potentially_region_dependent_goals,
118        check_type_wf: wfcheck::check_type_wf,
119        check_well_formed: wfcheck::check_well_formed,
120        ..*providers
121    };
122}
123
124fn adt_destructor(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<ty::Destructor> {
125    let dtor = tcx.calculate_dtor(def_id, always_applicable::check_drop_impl);
126    if dtor.is_none() && tcx.features().async_drop() {
127        if let Some(async_dtor) = adt_async_destructor(tcx, def_id) {
128            // When type has AsyncDrop impl, but doesn't have Drop impl, generate error
129            let span = tcx.def_span(async_dtor.impl_did);
130            tcx.dcx().emit_err(diagnostics::AsyncDropWithoutSyncDrop { span });
131        }
132    }
133    dtor
134}
135
136fn adt_async_destructor(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<ty::AsyncDestructor> {
137    let result = tcx.calculate_async_dtor(def_id, always_applicable::check_drop_impl);
138    // Async drop in libstd/libcore would become insta-stable — catch that mistake.
139    if result.is_some() && tcx.features().staged_api() {
140        ::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");
141    }
142    result
143}
144
145/// Given a `DefId` for an opaque type in return position, find its parent item's return
146/// expressions.
147fn get_owner_return_paths(
148    tcx: TyCtxt<'_>,
149    def_id: LocalDefId,
150) -> Option<(LocalDefId, ReturnsVisitor<'_>)> {
151    let hir_id = tcx.local_def_id_to_hir_id(def_id);
152    let parent_id = tcx.hir_get_parent_item(hir_id).def_id;
153    tcx.hir_node_by_def_id(parent_id).body_id().map(|body_id| {
154        let body = tcx.hir_body(body_id);
155        let mut visitor = ReturnsVisitor::default();
156        visitor.visit_body(body);
157        (parent_id, visitor)
158    })
159}
160
161pub(super) fn maybe_check_static_with_link_section(tcx: TyCtxt<'_>, id: LocalDefId) {
162    // Only restricted on wasm target for now
163    if !tcx.sess.target.is_like_wasm {
164        return;
165    }
166
167    // If `#[link_section]` is missing, then nothing to verify
168    let Some(link_section) = tcx.codegen_fn_attrs(id).link_section else {
169        return;
170    };
171
172    // For the wasm32 target statics with `#[link_section]` other than `.init_array`
173    // are placed into custom sections of the final output file, but this isn't like
174    // custom sections of other executable formats. Namely we can only embed a list
175    // of bytes, nothing with provenance (pointers to anything else). If any
176    // provenance show up, reject it here.
177    // `#[link_section]` may contain arbitrary, or even undefined bytes, but it is
178    // the consumer's responsibility to ensure all bytes that have been read
179    // have defined values.
180    //
181    // The `.init_array` section is left to go through the normal custom section code path.
182    // When dealing with `.init_array` wasm-ld currently has several limitations. This manifests
183    // in workarounds in user-code.
184    //
185    //   * The linker fails to merge multiple items in a crate into the .init_array section.
186    //     To work around this, a single array can be used placing multiple items in the array.
187    //     #[link_section = ".init_array"]
188    //     static FOO: [unsafe extern "C" fn(); 2] = [ctor, ctor];
189    //   * Even symbols marked used get gc'd from dependant crates unless at least one symbol
190    //     in the crate is marked with an `#[export_name]`
191    //
192    //  Once `.init_array` support in wasm-ld is complete, the user code workarounds should
193    //  continue to work, but would no longer be necessary.
194
195    if let Ok(alloc) = tcx.eval_static_initializer(id.to_def_id())
196        && !alloc.inner().provenance().ptrs().is_empty()
197        && !link_section.as_str().starts_with(".init_array")
198    {
199        let msg = "statics with a custom `#[link_section]` must be a \
200                        simple list of bytes on the wasm target with no \
201                        extra levels of indirection such as references";
202        tcx.dcx().span_err(tcx.def_span(id), msg);
203    }
204}
205
206fn missing_items_err(
207    tcx: TyCtxt<'_>,
208    impl_def_id: LocalDefId,
209    missing_items: &[ty::AssocItem],
210    full_impl_span: Span,
211) {
212    let missing_items =
213        missing_items.iter().filter(|trait_item| !trait_item.is_impl_trait_in_trait());
214
215    let missing_items_msg = missing_items
216        .clone()
217        .map(|trait_item| trait_item.name().to_string())
218        .collect::<Vec<_>>()
219        .join("`, `");
220
221    let sugg_sp = if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(full_impl_span)
222        && snippet.ends_with("}")
223    {
224        // `Span` before impl block closing brace.
225        let hi = full_impl_span.hi() - BytePos(1);
226        // Point at the place right before the closing brace of the relevant `impl` to suggest
227        // adding the associated item at the end of its body.
228        full_impl_span.with_lo(hi).with_hi(hi)
229    } else {
230        full_impl_span.shrink_to_hi()
231    };
232
233    // Obtain the level of indentation ending in `sugg_sp`.
234    let padding = tcx.sess.source_map().indentation_before(sugg_sp).unwrap_or_else(String::new);
235    let (mut missing_trait_item, mut missing_trait_item_none, mut missing_trait_item_label) =
236        (Vec::new(), Vec::new(), Vec::new());
237
238    for &trait_item in missing_items {
239        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(
240            tcx,
241            trait_item,
242            tcx.impl_trait_ref(impl_def_id).instantiate_identity().skip_norm_wip(),
243        ));
244        let code = ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0}{1}\n{0}", padding, snippet))
    })format!("{padding}{snippet}\n{padding}");
245        if let Some(span) = tcx.hir_span_if_local(trait_item.def_id) {
246            missing_trait_item_label
247                .push(diagnostics::MissingTraitItemLabel { span, item: trait_item.name() });
248            missing_trait_item.push(diagnostics::MissingTraitItemSuggestion {
249                span: sugg_sp,
250                code,
251                snippet,
252            });
253        } else {
254            missing_trait_item_none.push(diagnostics::MissingTraitItemSuggestionNone {
255                span: sugg_sp,
256                code,
257                snippet,
258            })
259        }
260    }
261
262    tcx.dcx().emit_err(diagnostics::MissingTraitItem {
263        span: tcx.span_of_impl(impl_def_id.to_def_id()).unwrap(),
264        missing_items_msg,
265        missing_trait_item_label,
266        missing_trait_item,
267        missing_trait_item_none,
268    });
269}
270
271fn missing_items_must_implement_one_of_err(
272    tcx: TyCtxt<'_>,
273    impl_span: Span,
274    missing_items: &[Ident],
275    annotation_span: Option<Span>,
276) {
277    let missing_items_msg =
278        missing_items.iter().map(Ident::to_string).collect::<Vec<_>>().join("`, `");
279
280    tcx.dcx().emit_err(diagnostics::MissingOneOfTraitItem {
281        span: impl_span,
282        note: annotation_span,
283        missing_items_msg,
284    });
285}
286
287fn default_body_is_unstable(
288    tcx: TyCtxt<'_>,
289    impl_span: Span,
290    item_did: DefId,
291    feature: Symbol,
292    reason: Option<Symbol>,
293    issue: Option<NonZero<u32>>,
294) {
295    let missing_item_name = tcx.item_ident(item_did);
296    let (mut some_note, mut none_note, mut reason_str) = (false, false, String::new());
297    match reason {
298        Some(r) => {
299            some_note = true;
300            reason_str = r.to_string();
301        }
302        None => none_note = true,
303    };
304
305    let mut err = tcx.dcx().create_err(diagnostics::MissingTraitItemUnstable {
306        span: impl_span,
307        some_note,
308        none_note,
309        missing_item_name,
310        feature,
311        reason: reason_str,
312    });
313
314    let inject_span = item_did.is_local().then(|| tcx.crate_level_attribute_injection_span());
315    rustc_session::errors::add_feature_diagnostics_for_issue(
316        &mut err,
317        &tcx.sess,
318        feature,
319        rustc_feature::GateIssue::Library(issue),
320        false,
321        inject_span,
322    );
323
324    err.emit();
325}
326
327/// Re-sugar `ty::GenericPredicates` in a way suitable to be used in structured suggestions.
328fn bounds_from_generic_predicates<'tcx>(
329    tcx: TyCtxt<'tcx>,
330    predicates: impl IntoIterator<Item = (ty::Clause<'tcx>, Span)>,
331    assoc: ty::AssocItem,
332) -> (String, String) {
333    let mut types: FxIndexMap<Ty<'tcx>, Vec<DefId>> = FxIndexMap::default();
334    let mut regions: FxIndexMap<Region<'tcx>, Vec<Region<'tcx>>> = FxIndexMap::default();
335    let mut projections = ::alloc::vec::Vec::new()vec![];
336    for (predicate, _) in predicates {
337        {
    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:337",
                        "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(337u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_hir_analysis::check"),
                        ::tracing_core::field::FieldSet::new(&["message"],
                            ::tracing_core::callsite::Identifier(&__CALLSITE)),
                        ::tracing::metadata::Kind::EVENT)
                };
            ::tracing::callsite::DefaultCallsite::new(&META)
        };
    let enabled =
        ::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::DEBUG <=
                    ::tracing::level_filters::LevelFilter::current() &&
            {
                let interest = __CALLSITE.interest();
                !interest.is_never() &&
                    ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                        interest)
            };
    if enabled {
        (|value_set: ::tracing::field::ValueSet|
                    {
                        let meta = __CALLSITE.metadata();
                        ::tracing::Event::dispatch(meta, &value_set);
                        ;
                    })({
                #[allow(unused_imports)]
                use ::tracing::field::{debug, display, Value};
                let mut iter = __CALLSITE.metadata().fields().iter();
                __CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                    ::tracing::__macro_support::Option::Some(&format_args!("predicate {0:?}",
                                                    predicate) as &dyn Value))])
            });
    } else { ; }
};debug!("predicate {:?}", predicate);
338        let bound_predicate = predicate.kind();
339        match bound_predicate.skip_binder() {
340            ty::ClauseKind::Trait(trait_predicate) => {
341                let entry = types.entry(trait_predicate.self_ty()).or_default();
342                let def_id = trait_predicate.def_id();
343                if !tcx.is_default_trait(def_id) && !tcx.is_lang_item(def_id, LangItem::Sized) {
344                    // Do not add that restriction to the list if it is a positive requirement.
345                    entry.push(trait_predicate.def_id());
346                }
347            }
348            ty::ClauseKind::Projection(projection_pred) => {
349                projections.push(bound_predicate.rebind(projection_pred));
350            }
351            ty::ClauseKind::RegionOutlives(OutlivesPredicate(a, b)) => {
352                regions.entry(a).or_default().push(b);
353            }
354            _ => {}
355        }
356    }
357
358    let mut where_clauses = ::alloc::vec::Vec::new()vec![];
359    let generics = tcx.generics_of(assoc.def_id);
360    let params = generics
361        .own_params
362        .iter()
363        .filter(|p| !p.kind.is_synthetic())
364        .map(|p| match tcx.mk_param_from_def(p).kind() {
365            ty::GenericArgKind::Type(ty) => {
366                let bounds =
367                    types.get(&ty).map(Cow::Borrowed).unwrap_or_else(|| Cow::Owned(Vec::new()));
368                let mut bounds_str = ::alloc::vec::Vec::new()vec![];
369                for bound in bounds.iter().copied() {
370                    let mut projections_str = ::alloc::vec::Vec::new()vec![];
371                    for projection in &projections {
372                        let p = projection.skip_binder();
373                        if bound == p.projection_term.trait_def_id(tcx)
374                            && p.projection_term.self_ty() == ty
375                        {
376                            let name = tcx.item_name(p.projection_term.expect_projection_def_id());
377                            projections_str.push(::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0} = {1}", name, p.term))
    })format!("{} = {}", name, p.term));
378                        }
379                    }
380                    let bound_def_path = if tcx.is_lang_item(bound, LangItem::MetaSized) {
381                        String::from("?Sized")
382                    } else {
383                        tcx.def_path_str(bound)
384                    };
385                    if projections_str.is_empty() {
386                        where_clauses.push(::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0}: {1}", ty, bound_def_path))
    })format!("{}: {}", ty, bound_def_path));
387                    } else {
388                        bounds_str.push(::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0}<{1}>", bound_def_path,
                projections_str.join(", ")))
    })format!(
389                            "{}<{}>",
390                            bound_def_path,
391                            projections_str.join(", ")
392                        ));
393                    }
394                }
395                if bounds_str.is_empty() {
396                    ty.to_string()
397                } else {
398                    ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0}: {1}", ty,
                bounds_str.join(" + ")))
    })format!("{}: {}", ty, bounds_str.join(" + "))
399                }
400            }
401            ty::GenericArgKind::Const(ct) => {
402                ::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())
403            }
404            ty::GenericArgKind::Lifetime(region) => {
405                if let Some(v) = regions.get(&region)
406                    && !v.is_empty()
407                {
408                    ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{1}: {0}",
                v.into_iter().map(Region::to_string).collect::<Vec<_>>().join(" + "),
                region))
    })format!(
409                        "{region}: {}",
410                        v.into_iter().map(Region::to_string).collect::<Vec<_>>().join(" + ")
411                    )
412                } else {
413                    region.to_string()
414                }
415            }
416        })
417        .collect::<Vec<_>>();
418    for (ty, bounds) in types.into_iter() {
419        if !#[allow(non_exhaustive_omitted_patterns)] match ty.kind() {
    ty::Param(_) => true,
    _ => false,
}matches!(ty.kind(), ty::Param(_)) {
420            // Avoid suggesting the following:
421            // fn foo<T, <T as Trait>::Bar>(_: T) where T: Trait, <T as Trait>::Bar: Other {}
422            where_clauses.extend(
423                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))),
424            );
425        }
426    }
427
428    let generics =
429        if params.is_empty() { "".to_string() } else { ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("<{0}>", params.join(", ")))
    })format!("<{}>", params.join(", ")) };
430
431    let where_clauses = if where_clauses.is_empty() {
432        "".to_string()
433    } else {
434        ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!(" where {0}",
                where_clauses.join(", ")))
    })format!(" where {}", where_clauses.join(", "))
435    };
436
437    (generics, where_clauses)
438}
439
440/// Return placeholder code for the given function.
441fn fn_sig_suggestion<'tcx>(
442    tcx: TyCtxt<'tcx>,
443    sig: ty::FnSig<'tcx>,
444    ident: Ident,
445    predicates: impl IntoIterator<Item = (ty::Clause<'tcx>, Span)>,
446    assoc: ty::AssocItem,
447) -> String {
448    let args = sig
449        .inputs()
450        .iter()
451        .enumerate()
452        .map(|(i, ty)| {
453            let arg_ty = match ty.kind() {
454                ty::Param(_) if assoc.is_method() && i == 0 => "self".to_string(),
455                ty::Ref(reg, ref_ty, mutability) if i == 0 => {
456                    let reg = ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0} ", reg))
    })format!("{reg} ");
457                    let reg = match &reg[..] {
458                        "'_ " | " " => "",
459                        reg => reg,
460                    };
461                    if assoc.is_method() {
462                        match ref_ty.kind() {
463                            ty::Param(param) if param.name == kw::SelfUpper => {
464                                ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("&{0}{1}self", reg,
                mutability.prefix_str()))
    })format!("&{}{}self", reg, mutability.prefix_str())
465                            }
466
467                            _ => ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("self: {0}", ty))
    })format!("self: {ty}"),
468                        }
469                    } else {
470                        ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("_: {0}", ty))
    })format!("_: {ty}")
471                    }
472                }
473                _ => {
474                    if assoc.is_method() && i == 0 {
475                        ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("self: {0}", ty))
    })format!("self: {ty}")
476                    } else {
477                        ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("_: {0}", ty))
    })format!("_: {ty}")
478                    }
479                }
480            };
481            Some(::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0}", arg_ty))
    })format!("{arg_ty}"))
482        })
483        .chain(std::iter::once(if sig.c_variadic() { Some("...".to_string()) } else { None }))
484        .flatten()
485        .collect::<Vec<String>>()
486        .join(", ");
487    let mut output = sig.output();
488
489    let asyncness = if tcx.asyncness(assoc.def_id).is_async() {
490        output = if let ty::Alias(alias_ty) = *output.kind()
491            && let Some(output) = tcx
492                .explicit_item_self_bounds(alias_ty.kind.def_id())
493                .iter_instantiated_copied(tcx, alias_ty.args)
494                .map(Unnormalized::skip_norm_wip)
495                .find_map(|(bound, _)| {
496                    bound.as_projection_clause()?.no_bound_vars()?.term.as_type()
497                }) {
498            output
499        } else {
500            ::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!(
501                ident.span,
502                "expected async fn to have `impl Future` output, but it returns {output}"
503            )
504        };
505        "async "
506    } else {
507        ""
508    };
509
510    let output = if !output.is_unit() { ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!(" -> {0}", output))
    })format!(" -> {output}") } else { String::new() };
511
512    let safety = sig.safety().prefix_str();
513    let (generics, where_clauses) = bounds_from_generic_predicates(tcx, predicates, assoc);
514
515    // FIXME: this is not entirely correct, as the lifetimes from borrowed params will
516    // not be present in the `fn` definition, nor will we account for renamed
517    // lifetimes between the `impl` and the `trait`, but this should be good enough to
518    // fill in a significant portion of the missing code, and other subsequent
519    // suggestions can help the user fix the code.
520    ::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!() }}")
521}
522
523/// Return placeholder code for the given associated item.
524/// Similar to `ty::AssocItem::suggestion`, but appropriate for use as the code snippet of a
525/// structured suggestion.
526fn suggestion_signature<'tcx>(
527    tcx: TyCtxt<'tcx>,
528    assoc: ty::AssocItem,
529    impl_trait_ref: ty::TraitRef<'tcx>,
530) -> String {
531    let args = ty::GenericArgs::identity_for_item(tcx, assoc.def_id).rebase_onto(
532        tcx,
533        assoc.container_id(tcx),
534        impl_trait_ref.with_replaced_self_ty(tcx, tcx.types.self_param).args,
535    );
536
537    match assoc.kind {
538        ty::AssocKind::Fn { .. } => fn_sig_suggestion(
539            tcx,
540            tcx.liberate_late_bound_regions(
541                assoc.def_id,
542                tcx.fn_sig(assoc.def_id).instantiate(tcx, args).skip_norm_wip(),
543            ),
544            assoc.ident(tcx),
545            tcx.predicates_of(assoc.def_id)
546                .instantiate_own(tcx, args)
547                .map(|(c, s)| (c.skip_norm_wip(), s)),
548            assoc,
549        ),
550        ty::AssocKind::Type { .. } => {
551            let (generics, where_clauses) = bounds_from_generic_predicates(
552                tcx,
553                tcx.predicates_of(assoc.def_id)
554                    .instantiate_own(tcx, args)
555                    .map(|(c, s)| (c.skip_norm_wip(), s)),
556                assoc,
557            );
558            ::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())
559        }
560        ty::AssocKind::Const { name, .. } => {
561            let ty = tcx.type_of(assoc.def_id).instantiate_identity().skip_norm_wip();
562            let val = tcx
563                .infer_ctxt()
564                .build(TypingMode::non_body_analysis())
565                .err_ctxt()
566                .ty_kind_suggestion(tcx.param_env(assoc.def_id), ty)
567                .unwrap_or_else(|| "value".to_string());
568            ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("const {0}: {1} = {2};", name, ty,
                val))
    })format!("const {}: {} = {};", name, ty, val)
569        }
570    }
571}
572
573/// Emit an error when encountering two or more variants in a transparent enum.
574fn bad_variant_count<'tcx>(tcx: TyCtxt<'tcx>, adt: ty::AdtDef<'tcx>, sp: Span, did: DefId) {
575    let variant_spans: Vec<_> = adt
576        .variants()
577        .iter()
578        .map(|variant| tcx.hir_span_if_local(variant.def_id).unwrap())
579        .collect();
580    let (mut spans, mut many) = (Vec::new(), None);
581    if let [start @ .., end] = &*variant_spans {
582        spans = start.to_vec();
583        many = Some(*end);
584    }
585    tcx.dcx().emit_err(diagnostics::TransparentEnumVariant {
586        span: sp,
587        spans,
588        many,
589        number: adt.variants().len(),
590        path: tcx.def_path_str(did),
591    });
592}
593
594// FIXME: Consider moving this method to a more fitting place.
595pub fn potentially_plural_count(count: usize, word: &str) -> String {
596    ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0} {1}{2}", count, word,
                if count == 1 { "" } else { "s" }))
    })format!("{} {}{}", count, word, pluralize!(count))
597}
598
599pub fn check_function_signature<'tcx>(
600    tcx: TyCtxt<'tcx>,
601    mut cause: ObligationCause<'tcx>,
602    fn_id: DefId,
603    expected_sig: ty::PolyFnSig<'tcx>,
604) -> Result<(), ErrorGuaranteed> {
605    fn extract_span_for_error_reporting<'tcx>(
606        tcx: TyCtxt<'tcx>,
607        err: TypeError<'_>,
608        cause: &ObligationCause<'tcx>,
609        fn_id: LocalDefId,
610    ) -> rustc_span::Span {
611        let mut args = {
612            let node = tcx.expect_hir_owner_node(fn_id);
613            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));
614            decl.inputs.iter().map(|t| t.span).chain(std::iter::once(decl.output.span()))
615        };
616
617        match err {
618            TypeError::ArgumentMutability(i)
619            | TypeError::ArgumentSorts(ExpectedFound { .. }, i) => args.nth(i).unwrap(),
620            _ => cause.span,
621        }
622    }
623
624    let local_id = fn_id.as_local().unwrap_or(CRATE_DEF_ID);
625
626    let param_env = ty::ParamEnv::empty();
627
628    let infcx = &tcx.infer_ctxt().build(TypingMode::non_body_analysis());
629    let ocx = ObligationCtxt::new_with_diagnostics(infcx);
630
631    let actual_sig = tcx.fn_sig(fn_id).instantiate_identity();
632
633    let norm_cause = ObligationCause::misc(cause.span, local_id);
634    let actual_sig = ocx.normalize(&norm_cause, param_env, actual_sig);
635
636    match ocx.eq(&cause, param_env, expected_sig, actual_sig) {
637        Ok(()) => {
638            let errors = ocx.evaluate_obligations_error_on_ambiguity();
639            if !errors.is_empty() {
640                return Err(infcx.err_ctxt().report_fulfillment_errors(errors));
641            }
642        }
643        Err(err) => {
644            let err_ctxt = infcx.err_ctxt();
645            if fn_id.is_local() {
646                cause.span = extract_span_for_error_reporting(tcx, err, &cause, local_id);
647            }
648            let failure_code = cause.as_failure_code_diag(err, cause.span, ::alloc::vec::Vec::new()vec![]);
649            let mut diag = tcx.dcx().create_err(failure_code);
650            err_ctxt.note_type_err(
651                &mut diag,
652                &cause,
653                None,
654                Some(param_env.and(infer::ValuePairs::PolySigs(ExpectedFound {
655                    expected: expected_sig,
656                    found: actual_sig,
657                }))),
658                err,
659                false,
660                None,
661            );
662            return Err(diag.emit());
663        }
664    }
665
666    if let Err(e) = ocx.resolve_regions_and_report_errors(local_id, param_env, []) {
667        return Err(e);
668    }
669
670    Ok(())
671}