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