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