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