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