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::{self, GenericArgs, GenericArgsRef, Ty, TyCtxt, TypingMode};
89use rustc_middle::{bug, span_bug};
90use rustc_session::parse::feature_err;
91use rustc_span::def_id::CRATE_DEF_ID;
92use rustc_span::{BytePos, DUMMY_SP, Ident, Span, Symbol, kw, sym};
93use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
94use rustc_trait_selection::error_reporting::infer::ObligationCauseExt as _;
95use rustc_trait_selection::error_reporting::traits::suggestions::ReturnsVisitor;
96use rustc_trait_selection::traits::ObligationCtxt;
97use tracing::debug;
98
99use self::compare_impl_item::collect_return_position_impl_trait_in_trait_tys;
100use self::region::region_scope_tree;
101use crate::{errors, require_c_abi_if_c_variadic};
102
103pub fn provide(providers: &mut Providers) {
104    wfcheck::provide(providers);
105    *providers = Providers {
106        adt_destructor,
107        adt_async_destructor,
108        region_scope_tree,
109        collect_return_position_impl_trait_in_trait_tys,
110        compare_impl_item: compare_impl_item::compare_impl_item,
111        check_coroutine_obligations: check::check_coroutine_obligations,
112        ..*providers
113    };
114}
115
116fn adt_destructor(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<ty::Destructor> {
117    let dtor = tcx.calculate_dtor(def_id, always_applicable::check_drop_impl);
118    if dtor.is_none() && tcx.features().async_drop() {
119        if let Some(async_dtor) = adt_async_destructor(tcx, def_id) {
120            // When type has AsyncDrop impl, but doesn't have Drop impl, generate error
121            let span = tcx.def_span(async_dtor.impl_did);
122            tcx.dcx().emit_err(errors::AsyncDropWithoutSyncDrop { span });
123        }
124    }
125    dtor
126}
127
128fn adt_async_destructor(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<ty::AsyncDestructor> {
129    tcx.calculate_async_dtor(def_id, always_applicable::check_drop_impl)
130}
131
132/// Given a `DefId` for an opaque type in return position, find its parent item's return
133/// expressions.
134fn get_owner_return_paths(
135    tcx: TyCtxt<'_>,
136    def_id: LocalDefId,
137) -> Option<(LocalDefId, ReturnsVisitor<'_>)> {
138    let hir_id = tcx.local_def_id_to_hir_id(def_id);
139    let parent_id = tcx.hir_get_parent_item(hir_id).def_id;
140    tcx.hir_node_by_def_id(parent_id).body_id().map(|body_id| {
141        let body = tcx.hir_body(body_id);
142        let mut visitor = ReturnsVisitor::default();
143        visitor.visit_body(body);
144        (parent_id, visitor)
145    })
146}
147
148pub(super) fn maybe_check_static_with_link_section(tcx: TyCtxt<'_>, id: LocalDefId) {
149    // Only restricted on wasm target for now
150    if !tcx.sess.target.is_like_wasm {
151        return;
152    }
153
154    // If `#[link_section]` is missing, then nothing to verify
155    let Some(link_section) = tcx.codegen_fn_attrs(id).link_section else {
156        return;
157    };
158
159    // For the wasm32 target statics with `#[link_section]` other than `.init_array`
160    // are placed into custom sections of the final output file, but this isn't like
161    // custom sections of other executable formats. Namely we can only embed a list
162    // of bytes, nothing with provenance (pointers to anything else). If any
163    // provenance show up, reject it here.
164    // `#[link_section]` may contain arbitrary, or even undefined bytes, but it is
165    // the consumer's responsibility to ensure all bytes that have been read
166    // have defined values.
167    //
168    // The `.init_array` section is left to go through the normal custom section code path.
169    // When dealing with `.init_array` wasm-ld currently has several limitations. This manifests
170    // in workarounds in user-code.
171    //
172    //   * The linker fails to merge multiple items in a crate into the .init_array section.
173    //     To work around this, a single array can be used placing multiple items in the array.
174    //     #[link_section = ".init_array"]
175    //     static FOO: [unsafe extern "C" fn(); 2] = [ctor, ctor];
176    //   * Even symbols marked used get gc'd from dependant crates unless at least one symbol
177    //     in the crate is marked with an `#[export_name]`
178    //
179    //  Once `.init_array` support in wasm-ld is complete, the user code workarounds should
180    //  continue to work, but would no longer be necessary.
181
182    if let Ok(alloc) = tcx.eval_static_initializer(id.to_def_id())
183        && !alloc.inner().provenance().ptrs().is_empty()
184        && !link_section.as_str().starts_with(".init_array")
185    {
186        let msg = "statics with a custom `#[link_section]` must be a \
187                        simple list of bytes on the wasm target with no \
188                        extra levels of indirection such as references";
189        tcx.dcx().span_err(tcx.def_span(id), msg);
190    }
191}
192
193fn report_forbidden_specialization(tcx: TyCtxt<'_>, impl_item: DefId, parent_impl: DefId) {
194    let span = tcx.def_span(impl_item);
195    let ident = tcx.item_ident(impl_item);
196
197    let err = match tcx.span_of_impl(parent_impl) {
198        Ok(sp) => errors::ImplNotMarkedDefault::Ok { span, ident, ok_label: sp },
199        Err(cname) => errors::ImplNotMarkedDefault::Err { span, ident, cname },
200    };
201
202    tcx.dcx().emit_err(err);
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 =
234        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 = with_types_for_signature!(suggestion_signature(
240            tcx,
241            trait_item,
242            tcx.impl_trait_ref(impl_def_id).unwrap().instantiate_identity(),
243        ));
244        let code = 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) -> (String, String) {
332    let mut types: FxIndexMap<Ty<'tcx>, Vec<DefId>> = FxIndexMap::default();
333    let mut projections = vec![];
334    for (predicate, _) in predicates {
335        debug!("predicate {:?}", predicate);
336        let bound_predicate = predicate.kind();
337        match bound_predicate.skip_binder() {
338            ty::ClauseKind::Trait(trait_predicate) => {
339                let entry = types.entry(trait_predicate.self_ty()).or_default();
340                let def_id = trait_predicate.def_id();
341                if !tcx.is_default_trait(def_id) && !tcx.is_lang_item(def_id, LangItem::Sized) {
342                    // Do not add that restriction to the list if it is a positive requirement.
343                    entry.push(trait_predicate.def_id());
344                }
345            }
346            ty::ClauseKind::Projection(projection_pred) => {
347                projections.push(bound_predicate.rebind(projection_pred));
348            }
349            _ => {}
350        }
351    }
352
353    let mut where_clauses = vec![];
354    let mut types_str = vec![];
355    for (ty, bounds) in types {
356        if let ty::Param(_) = ty.kind() {
357            let mut bounds_str = vec![];
358            for bound in bounds {
359                let mut projections_str = vec![];
360                for projection in &projections {
361                    let p = projection.skip_binder();
362                    if bound == tcx.parent(p.projection_term.def_id)
363                        && p.projection_term.self_ty() == ty
364                    {
365                        let name = tcx.item_name(p.projection_term.def_id);
366                        projections_str.push(format!("{} = {}", name, p.term));
367                    }
368                }
369                let bound_def_path = tcx.def_path_str(bound);
370                if projections_str.is_empty() {
371                    where_clauses.push(format!("{}: {}", ty, bound_def_path));
372                } else {
373                    bounds_str.push(format!("{}<{}>", bound_def_path, projections_str.join(", ")));
374                }
375            }
376            if bounds_str.is_empty() {
377                types_str.push(ty.to_string());
378            } else {
379                types_str.push(format!("{}: {}", ty, bounds_str.join(" + ")));
380            }
381        } else {
382            // Avoid suggesting the following:
383            // fn foo<T, <T as Trait>::Bar>(_: T) where T: Trait, <T as Trait>::Bar: Other {}
384            where_clauses.extend(
385                bounds.into_iter().map(|bound| format!("{}: {}", ty, tcx.def_path_str(bound))),
386            );
387        }
388    }
389
390    let generics =
391        if types_str.is_empty() { "".to_string() } else { format!("<{}>", types_str.join(", ")) };
392
393    let where_clauses = if where_clauses.is_empty() {
394        "".to_string()
395    } else {
396        format!(" where {}", where_clauses.join(", "))
397    };
398
399    (generics, where_clauses)
400}
401
402/// Return placeholder code for the given function.
403fn fn_sig_suggestion<'tcx>(
404    tcx: TyCtxt<'tcx>,
405    sig: ty::FnSig<'tcx>,
406    ident: Ident,
407    predicates: impl IntoIterator<Item = (ty::Clause<'tcx>, Span)>,
408    assoc: ty::AssocItem,
409) -> String {
410    let args = sig
411        .inputs()
412        .iter()
413        .enumerate()
414        .map(|(i, ty)| {
415            Some(match ty.kind() {
416                ty::Param(_) if assoc.is_method() && i == 0 => "self".to_string(),
417                ty::Ref(reg, ref_ty, mutability) if i == 0 => {
418                    let reg = format!("{reg} ");
419                    let reg = match &reg[..] {
420                        "'_ " | " " => "",
421                        reg => reg,
422                    };
423                    if assoc.is_method() {
424                        match ref_ty.kind() {
425                            ty::Param(param) if param.name == kw::SelfUpper => {
426                                format!("&{}{}self", reg, mutability.prefix_str())
427                            }
428
429                            _ => format!("self: {ty}"),
430                        }
431                    } else {
432                        format!("_: {ty}")
433                    }
434                }
435                _ => {
436                    if assoc.is_method() && i == 0 {
437                        format!("self: {ty}")
438                    } else {
439                        format!("_: {ty}")
440                    }
441                }
442            })
443        })
444        .chain(std::iter::once(if sig.c_variadic { Some("...".to_string()) } else { None }))
445        .flatten()
446        .collect::<Vec<String>>()
447        .join(", ");
448    let mut output = sig.output();
449
450    let asyncness = if tcx.asyncness(assoc.def_id).is_async() {
451        output = if let ty::Alias(_, alias_ty) = *output.kind()
452            && let Some(output) = tcx
453                .explicit_item_self_bounds(alias_ty.def_id)
454                .iter_instantiated_copied(tcx, alias_ty.args)
455                .find_map(|(bound, _)| {
456                    bound.as_projection_clause()?.no_bound_vars()?.term.as_type()
457                }) {
458            output
459        } else {
460            span_bug!(
461                ident.span,
462                "expected async fn to have `impl Future` output, but it returns {output}"
463            )
464        };
465        "async "
466    } else {
467        ""
468    };
469
470    let output = if !output.is_unit() { format!(" -> {output}") } else { String::new() };
471
472    let safety = sig.safety.prefix_str();
473    let (generics, where_clauses) = bounds_from_generic_predicates(tcx, predicates);
474
475    // FIXME: this is not entirely correct, as the lifetimes from borrowed params will
476    // not be present in the `fn` definition, not will we account for renamed
477    // lifetimes between the `impl` and the `trait`, but this should be good enough to
478    // fill in a significant portion of the missing code, and other subsequent
479    // suggestions can help the user fix the code.
480    format!("{safety}{asyncness}fn {ident}{generics}({args}){output}{where_clauses} {{ todo!() }}")
481}
482
483/// Return placeholder code for the given associated item.
484/// Similar to `ty::AssocItem::suggestion`, but appropriate for use as the code snippet of a
485/// structured suggestion.
486fn suggestion_signature<'tcx>(
487    tcx: TyCtxt<'tcx>,
488    assoc: ty::AssocItem,
489    impl_trait_ref: ty::TraitRef<'tcx>,
490) -> String {
491    let args = ty::GenericArgs::identity_for_item(tcx, assoc.def_id).rebase_onto(
492        tcx,
493        assoc.container_id(tcx),
494        impl_trait_ref.with_self_ty(tcx, tcx.types.self_param).args,
495    );
496
497    match assoc.kind {
498        ty::AssocKind::Fn { .. } => fn_sig_suggestion(
499            tcx,
500            tcx.liberate_late_bound_regions(
501                assoc.def_id,
502                tcx.fn_sig(assoc.def_id).instantiate(tcx, args),
503            ),
504            assoc.ident(tcx),
505            tcx.predicates_of(assoc.def_id).instantiate_own(tcx, args),
506            assoc,
507        ),
508        ty::AssocKind::Type { .. } => {
509            let (generics, where_clauses) = bounds_from_generic_predicates(
510                tcx,
511                tcx.predicates_of(assoc.def_id).instantiate_own(tcx, args),
512            );
513            format!("type {}{generics} = /* Type */{where_clauses};", assoc.name())
514        }
515        ty::AssocKind::Const { name } => {
516            let ty = tcx.type_of(assoc.def_id).instantiate_identity();
517            let val = tcx
518                .infer_ctxt()
519                .build(TypingMode::non_body_analysis())
520                .err_ctxt()
521                .ty_kind_suggestion(tcx.param_env(assoc.def_id), ty)
522                .unwrap_or_else(|| "value".to_string());
523            format!("const {}: {} = {};", name, ty, val)
524        }
525    }
526}
527
528/// Emit an error when encountering two or more variants in a transparent enum.
529fn bad_variant_count<'tcx>(tcx: TyCtxt<'tcx>, adt: ty::AdtDef<'tcx>, sp: Span, did: DefId) {
530    let variant_spans: Vec<_> = adt
531        .variants()
532        .iter()
533        .map(|variant| tcx.hir_span_if_local(variant.def_id).unwrap())
534        .collect();
535    let (mut spans, mut many) = (Vec::new(), None);
536    if let [start @ .., end] = &*variant_spans {
537        spans = start.to_vec();
538        many = Some(*end);
539    }
540    tcx.dcx().emit_err(errors::TransparentEnumVariant {
541        span: sp,
542        spans,
543        many,
544        number: adt.variants().len(),
545        path: tcx.def_path_str(did),
546    });
547}
548
549/// Emit an error when encountering two or more non-zero-sized fields in a transparent
550/// enum.
551fn bad_non_zero_sized_fields<'tcx>(
552    tcx: TyCtxt<'tcx>,
553    adt: ty::AdtDef<'tcx>,
554    field_count: usize,
555    field_spans: impl Iterator<Item = Span>,
556    sp: Span,
557) {
558    if adt.is_enum() {
559        tcx.dcx().emit_err(errors::TransparentNonZeroSizedEnum {
560            span: sp,
561            spans: field_spans.collect(),
562            field_count,
563            desc: adt.descr(),
564        });
565    } else {
566        tcx.dcx().emit_err(errors::TransparentNonZeroSized {
567            span: sp,
568            spans: field_spans.collect(),
569            field_count,
570            desc: adt.descr(),
571        });
572    }
573}
574
575// FIXME: Consider moving this method to a more fitting place.
576pub fn potentially_plural_count(count: usize, word: &str) -> String {
577    format!("{} {}{}", count, word, pluralize!(count))
578}
579
580pub fn check_function_signature<'tcx>(
581    tcx: TyCtxt<'tcx>,
582    mut cause: ObligationCause<'tcx>,
583    fn_id: DefId,
584    expected_sig: ty::PolyFnSig<'tcx>,
585) -> Result<(), ErrorGuaranteed> {
586    fn extract_span_for_error_reporting<'tcx>(
587        tcx: TyCtxt<'tcx>,
588        err: TypeError<'_>,
589        cause: &ObligationCause<'tcx>,
590        fn_id: LocalDefId,
591    ) -> rustc_span::Span {
592        let mut args = {
593            let node = tcx.expect_hir_owner_node(fn_id);
594            let decl = node.fn_decl().unwrap_or_else(|| bug!("expected fn decl, found {:?}", node));
595            decl.inputs.iter().map(|t| t.span).chain(std::iter::once(decl.output.span()))
596        };
597
598        match err {
599            TypeError::ArgumentMutability(i)
600            | TypeError::ArgumentSorts(ExpectedFound { .. }, i) => args.nth(i).unwrap(),
601            _ => cause.span,
602        }
603    }
604
605    let local_id = fn_id.as_local().unwrap_or(CRATE_DEF_ID);
606
607    let param_env = ty::ParamEnv::empty();
608
609    let infcx = &tcx.infer_ctxt().build(TypingMode::non_body_analysis());
610    let ocx = ObligationCtxt::new_with_diagnostics(infcx);
611
612    let actual_sig = tcx.fn_sig(fn_id).instantiate_identity();
613
614    let norm_cause = ObligationCause::misc(cause.span, local_id);
615    let actual_sig = ocx.normalize(&norm_cause, param_env, actual_sig);
616
617    match ocx.eq(&cause, param_env, expected_sig, actual_sig) {
618        Ok(()) => {
619            let errors = ocx.select_all_or_error();
620            if !errors.is_empty() {
621                return Err(infcx.err_ctxt().report_fulfillment_errors(errors));
622            }
623        }
624        Err(err) => {
625            let err_ctxt = infcx.err_ctxt();
626            if fn_id.is_local() {
627                cause.span = extract_span_for_error_reporting(tcx, err, &cause, local_id);
628            }
629            let failure_code = cause.as_failure_code_diag(err, cause.span, vec![]);
630            let mut diag = tcx.dcx().create_err(failure_code);
631            err_ctxt.note_type_err(
632                &mut diag,
633                &cause,
634                None,
635                Some(param_env.and(infer::ValuePairs::PolySigs(ExpectedFound {
636                    expected: expected_sig,
637                    found: actual_sig,
638                }))),
639                err,
640                false,
641                None,
642            );
643            return Err(diag.emit());
644        }
645    }
646
647    if let Err(e) = ocx.resolve_regions_and_report_errors(local_id, param_env, []) {
648        return Err(e);
649    }
650
651    Ok(())
652}