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::parse::feature_err;
96use rustc_span::def_id::CRATE_DEF_ID;
97use rustc_span::{BytePos, DUMMY_SP, Ident, Span, Symbol, kw, sym};
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, errors};
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(errors::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(errors::MissingTraitItemLabel { span, item: trait_item.name() });
248            missing_trait_item.push(errors::MissingTraitItemSuggestion {
249                span: sugg_sp,
250                code,
251                snippet,
252            });
253        } else {
254            missing_trait_item_none.push(errors::MissingTraitItemSuggestionNone {
255                span: sugg_sp,
256                code,
257                snippet,
258            })
259        }
260    }
261
262    tcx.dcx().emit_err(errors::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(errors::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(errors::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::parse::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 == tcx.parent(p.projection_term.def_id())
374                            && p.projection_term.self_ty() == ty
375                        {
376                            let name = tcx.item_name(p.projection_term.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            Some(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        })
482        .chain(std::iter::once(if sig.c_variadic() { Some("...".to_string()) } else { None }))
483        .flatten()
484        .collect::<Vec<String>>()
485        .join(", ");
486    let mut output = sig.output();
487
488    let asyncness = if tcx.asyncness(assoc.def_id).is_async() {
489        output = if let ty::Alias(alias_ty) = *output.kind()
490            && let Some(output) = tcx
491                .explicit_item_self_bounds(alias_ty.kind.def_id())
492                .iter_instantiated_copied(tcx, alias_ty.args)
493                .map(Unnormalized::skip_norm_wip)
494                .find_map(|(bound, _)| {
495                    bound.as_projection_clause()?.no_bound_vars()?.term.as_type()
496                }) {
497            output
498        } else {
499            ::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!(
500                ident.span,
501                "expected async fn to have `impl Future` output, but it returns {output}"
502            )
503        };
504        "async "
505    } else {
506        ""
507    };
508
509    let output = if !output.is_unit() { ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!(" -> {0}", output))
    })format!(" -> {output}") } else { String::new() };
510
511    let safety = sig.safety().prefix_str();
512    let (generics, where_clauses) = bounds_from_generic_predicates(tcx, predicates, assoc);
513
514    // FIXME: this is not entirely correct, as the lifetimes from borrowed params will
515    // not be present in the `fn` definition, nor will we account for renamed
516    // lifetimes between the `impl` and the `trait`, but this should be good enough to
517    // fill in a significant portion of the missing code, and other subsequent
518    // suggestions can help the user fix the code.
519    ::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!() }}")
520}
521
522/// Return placeholder code for the given associated item.
523/// Similar to `ty::AssocItem::suggestion`, but appropriate for use as the code snippet of a
524/// structured suggestion.
525fn suggestion_signature<'tcx>(
526    tcx: TyCtxt<'tcx>,
527    assoc: ty::AssocItem,
528    impl_trait_ref: ty::TraitRef<'tcx>,
529) -> String {
530    let args = ty::GenericArgs::identity_for_item(tcx, assoc.def_id).rebase_onto(
531        tcx,
532        assoc.container_id(tcx),
533        impl_trait_ref.with_replaced_self_ty(tcx, tcx.types.self_param).args,
534    );
535
536    match assoc.kind {
537        ty::AssocKind::Fn { .. } => fn_sig_suggestion(
538            tcx,
539            tcx.liberate_late_bound_regions(
540                assoc.def_id,
541                tcx.fn_sig(assoc.def_id).instantiate(tcx, args).skip_norm_wip(),
542            ),
543            assoc.ident(tcx),
544            tcx.predicates_of(assoc.def_id)
545                .instantiate_own(tcx, args)
546                .map(|(c, s)| (c.skip_norm_wip(), s)),
547            assoc,
548        ),
549        ty::AssocKind::Type { .. } => {
550            let (generics, where_clauses) = bounds_from_generic_predicates(
551                tcx,
552                tcx.predicates_of(assoc.def_id)
553                    .instantiate_own(tcx, args)
554                    .map(|(c, s)| (c.skip_norm_wip(), s)),
555                assoc,
556            );
557            ::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())
558        }
559        ty::AssocKind::Const { name, .. } => {
560            let ty = tcx.type_of(assoc.def_id).instantiate_identity().skip_norm_wip();
561            let val = tcx
562                .infer_ctxt()
563                .build(TypingMode::non_body_analysis())
564                .err_ctxt()
565                .ty_kind_suggestion(tcx.param_env(assoc.def_id), ty)
566                .unwrap_or_else(|| "value".to_string());
567            ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("const {0}: {1} = {2};", name, ty,
                val))
    })format!("const {}: {} = {};", name, ty, val)
568        }
569    }
570}
571
572/// Emit an error when encountering two or more variants in a transparent enum.
573fn bad_variant_count<'tcx>(tcx: TyCtxt<'tcx>, adt: ty::AdtDef<'tcx>, sp: Span, did: DefId) {
574    let variant_spans: Vec<_> = adt
575        .variants()
576        .iter()
577        .map(|variant| tcx.hir_span_if_local(variant.def_id).unwrap())
578        .collect();
579    let (mut spans, mut many) = (Vec::new(), None);
580    if let [start @ .., end] = &*variant_spans {
581        spans = start.to_vec();
582        many = Some(*end);
583    }
584    tcx.dcx().emit_err(errors::TransparentEnumVariant {
585        span: sp,
586        spans,
587        many,
588        number: adt.variants().len(),
589        path: tcx.def_path_str(did),
590    });
591}
592
593/// Emit an error when encountering two or more non-zero-sized fields in a transparent
594/// enum.
595fn bad_non_zero_sized_fields<'tcx>(
596    tcx: TyCtxt<'tcx>,
597    adt: ty::AdtDef<'tcx>,
598    field_count: usize,
599    field_spans: impl Iterator<Item = Span>,
600    sp: Span,
601) {
602    if adt.is_enum() {
603        tcx.dcx().emit_err(errors::TransparentNonZeroSizedEnum {
604            span: sp,
605            spans: field_spans.collect(),
606            field_count,
607            desc: adt.descr(),
608        });
609    } else {
610        tcx.dcx().emit_err(errors::TransparentNonZeroSized {
611            span: sp,
612            spans: field_spans.collect(),
613            field_count,
614            desc: adt.descr(),
615        });
616    }
617}
618
619// FIXME: Consider moving this method to a more fitting place.
620pub fn potentially_plural_count(count: usize, word: &str) -> String {
621    ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0} {1}{2}", count, word,
                if count == 1 { "" } else { "s" }))
    })format!("{} {}{}", count, word, pluralize!(count))
622}
623
624pub fn check_function_signature<'tcx>(
625    tcx: TyCtxt<'tcx>,
626    mut cause: ObligationCause<'tcx>,
627    fn_id: DefId,
628    expected_sig: ty::PolyFnSig<'tcx>,
629) -> Result<(), ErrorGuaranteed> {
630    fn extract_span_for_error_reporting<'tcx>(
631        tcx: TyCtxt<'tcx>,
632        err: TypeError<'_>,
633        cause: &ObligationCause<'tcx>,
634        fn_id: LocalDefId,
635    ) -> rustc_span::Span {
636        let mut args = {
637            let node = tcx.expect_hir_owner_node(fn_id);
638            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));
639            decl.inputs.iter().map(|t| t.span).chain(std::iter::once(decl.output.span()))
640        };
641
642        match err {
643            TypeError::ArgumentMutability(i)
644            | TypeError::ArgumentSorts(ExpectedFound { .. }, i) => args.nth(i).unwrap(),
645            _ => cause.span,
646        }
647    }
648
649    let local_id = fn_id.as_local().unwrap_or(CRATE_DEF_ID);
650
651    let param_env = ty::ParamEnv::empty();
652
653    let infcx = &tcx.infer_ctxt().build(TypingMode::non_body_analysis());
654    let ocx = ObligationCtxt::new_with_diagnostics(infcx);
655
656    let actual_sig = tcx.fn_sig(fn_id).instantiate_identity();
657
658    let norm_cause = ObligationCause::misc(cause.span, local_id);
659    let actual_sig = ocx.normalize(&norm_cause, param_env, actual_sig);
660
661    match ocx.eq(&cause, param_env, expected_sig, actual_sig) {
662        Ok(()) => {
663            let errors = ocx.evaluate_obligations_error_on_ambiguity();
664            if !errors.is_empty() {
665                return Err(infcx.err_ctxt().report_fulfillment_errors(errors));
666            }
667        }
668        Err(err) => {
669            let err_ctxt = infcx.err_ctxt();
670            if fn_id.is_local() {
671                cause.span = extract_span_for_error_reporting(tcx, err, &cause, local_id);
672            }
673            let failure_code = cause.as_failure_code_diag(err, cause.span, ::alloc::vec::Vec::new()vec![]);
674            let mut diag = tcx.dcx().create_err(failure_code);
675            err_ctxt.note_type_err(
676                &mut diag,
677                &cause,
678                None,
679                Some(param_env.and(infer::ValuePairs::PolySigs(ExpectedFound {
680                    expected: expected_sig,
681                    found: actual_sig,
682                }))),
683                err,
684                false,
685                None,
686            );
687            return Err(diag.emit());
688        }
689    }
690
691    if let Err(e) = ocx.resolve_regions_and_report_errors(local_id, param_env, []) {
692        return Err(e);
693    }
694
695    Ok(())
696}