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