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
65mod check;
66mod compare_impl_item;
67pub mod dropck;
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::{self, GenericArgs, GenericArgsRef, Ty, TyCtxt, TypingMode};
88use rustc_middle::{bug, span_bug};
89use rustc_session::parse::feature_err;
90use rustc_span::def_id::CRATE_DEF_ID;
91use rustc_span::{BytePos, DUMMY_SP, Ident, Span, Symbol, kw, sym};
92use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
93use rustc_trait_selection::error_reporting::infer::ObligationCauseExt as _;
94use rustc_trait_selection::error_reporting::traits::suggestions::ReturnsVisitor;
95use rustc_trait_selection::traits::ObligationCtxt;
96use tracing::debug;
97
98use self::compare_impl_item::collect_return_position_impl_trait_in_trait_tys;
99use self::region::region_scope_tree;
100use crate::{errors, require_c_abi_if_c_variadic};
101
102pub fn provide(providers: &mut Providers) {
103    wfcheck::provide(providers);
104    *providers = Providers {
105        adt_destructor,
106        adt_async_destructor,
107        region_scope_tree,
108        collect_return_position_impl_trait_in_trait_tys,
109        compare_impl_item: compare_impl_item::compare_impl_item,
110        check_coroutine_obligations: check::check_coroutine_obligations,
111        ..*providers
112    };
113}
114
115fn adt_destructor(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<ty::Destructor> {
116    tcx.calculate_dtor(def_id.to_def_id(), dropck::check_drop_impl)
117}
118
119fn adt_async_destructor(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<ty::AsyncDestructor> {
120    tcx.calculate_async_dtor(def_id.to_def_id(), dropck::check_drop_impl)
121}
122
123/// Given a `DefId` for an opaque type in return position, find its parent item's return
124/// expressions.
125fn get_owner_return_paths(
126    tcx: TyCtxt<'_>,
127    def_id: LocalDefId,
128) -> Option<(LocalDefId, ReturnsVisitor<'_>)> {
129    let hir_id = tcx.local_def_id_to_hir_id(def_id);
130    let parent_id = tcx.hir().get_parent_item(hir_id).def_id;
131    tcx.hir_node_by_def_id(parent_id).body_id().map(|body_id| {
132        let body = tcx.hir().body(body_id);
133        let mut visitor = ReturnsVisitor::default();
134        visitor.visit_body(body);
135        (parent_id, visitor)
136    })
137}
138
139/// Forbid defining intrinsics in Rust code,
140/// as they must always be defined by the compiler.
141// FIXME: Move this to a more appropriate place.
142pub fn forbid_intrinsic_abi(tcx: TyCtxt<'_>, sp: Span, abi: ExternAbi) {
143    if let ExternAbi::RustIntrinsic = abi {
144        tcx.dcx().span_err(sp, "intrinsic must be in `extern \"rust-intrinsic\" { ... }` block");
145    }
146}
147
148fn 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 attrs = tcx.codegen_fn_attrs(id);
156    if attrs.link_section.is_none() {
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().len() != 0
185        && attrs
186            .link_section
187            .map(|link_section| !link_section.as_str().starts_with(".init_array"))
188            .unwrap()
189    {
190        let msg = "statics with a custom `#[link_section]` must be a \
191                        simple list of bytes on the wasm target with no \
192                        extra levels of indirection such as references";
193        tcx.dcx().span_err(tcx.def_span(id), msg);
194    }
195}
196
197fn report_forbidden_specialization(tcx: TyCtxt<'_>, impl_item: DefId, parent_impl: DefId) {
198    let span = tcx.def_span(impl_item);
199    let ident = tcx.item_ident(impl_item);
200
201    let err = match tcx.span_of_impl(parent_impl) {
202        Ok(sp) => errors::ImplNotMarkedDefault::Ok { span, ident, ok_label: sp },
203        Err(cname) => errors::ImplNotMarkedDefault::Err { span, ident, cname },
204    };
205
206    tcx.dcx().emit_err(err);
207}
208
209fn missing_items_err(
210    tcx: TyCtxt<'_>,
211    impl_def_id: LocalDefId,
212    missing_items: &[ty::AssocItem],
213    full_impl_span: Span,
214) {
215    let missing_items =
216        missing_items.iter().filter(|trait_item| !trait_item.is_impl_trait_in_trait());
217
218    let missing_items_msg = missing_items
219        .clone()
220        .map(|trait_item| trait_item.name.to_string())
221        .collect::<Vec<_>>()
222        .join("`, `");
223
224    let sugg_sp = if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(full_impl_span)
225        && snippet.ends_with("}")
226    {
227        // `Span` before impl block closing brace.
228        let hi = full_impl_span.hi() - BytePos(1);
229        // Point at the place right before the closing brace of the relevant `impl` to suggest
230        // adding the associated item at the end of its body.
231        full_impl_span.with_lo(hi).with_hi(hi)
232    } else {
233        full_impl_span.shrink_to_hi()
234    };
235
236    // Obtain the level of indentation ending in `sugg_sp`.
237    let padding =
238        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 = 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
319        .as_local()
320        .and_then(|id| tcx.crate_level_attribute_injection_span(tcx.local_def_id_to_hir_id(id)));
321    rustc_session::parse::add_feature_diagnostics_for_issue(
322        &mut err,
323        &tcx.sess,
324        feature,
325        rustc_feature::GateIssue::Library(issue),
326        false,
327        inject_span,
328    );
329
330    err.emit();
331}
332
333/// Re-sugar `ty::GenericPredicates` in a way suitable to be used in structured suggestions.
334fn bounds_from_generic_predicates<'tcx>(
335    tcx: TyCtxt<'tcx>,
336    predicates: impl IntoIterator<Item = (ty::Clause<'tcx>, Span)>,
337) -> (String, String) {
338    let mut types: FxIndexMap<Ty<'tcx>, Vec<DefId>> = FxIndexMap::default();
339    let mut projections = vec![];
340    for (predicate, _) in predicates {
341        debug!("predicate {:?}", predicate);
342        let bound_predicate = predicate.kind();
343        match bound_predicate.skip_binder() {
344            ty::ClauseKind::Trait(trait_predicate) => {
345                let entry = types.entry(trait_predicate.self_ty()).or_default();
346                let def_id = trait_predicate.def_id();
347                if Some(def_id) != tcx.lang_items().sized_trait() {
348                    // Type params are `Sized` by default, do not add that restriction to the list
349                    // if it is a positive requirement.
350                    entry.push(trait_predicate.def_id());
351                }
352            }
353            ty::ClauseKind::Projection(projection_pred) => {
354                projections.push(bound_predicate.rebind(projection_pred));
355            }
356            _ => {}
357        }
358    }
359
360    let mut where_clauses = vec![];
361    let mut types_str = vec![];
362    for (ty, bounds) in types {
363        if let ty::Param(_) = ty.kind() {
364            let mut bounds_str = vec![];
365            for bound in bounds {
366                let mut projections_str = vec![];
367                for projection in &projections {
368                    let p = projection.skip_binder();
369                    if bound == tcx.parent(p.projection_term.def_id)
370                        && p.projection_term.self_ty() == ty
371                    {
372                        let name = tcx.item_name(p.projection_term.def_id);
373                        projections_str.push(format!("{} = {}", name, p.term));
374                    }
375                }
376                let bound_def_path = tcx.def_path_str(bound);
377                if projections_str.is_empty() {
378                    where_clauses.push(format!("{}: {}", ty, bound_def_path));
379                } else {
380                    bounds_str.push(format!("{}<{}>", bound_def_path, projections_str.join(", ")));
381                }
382            }
383            if bounds_str.is_empty() {
384                types_str.push(ty.to_string());
385            } else {
386                types_str.push(format!("{}: {}", ty, bounds_str.join(" + ")));
387            }
388        } else {
389            // Avoid suggesting the following:
390            // fn foo<T, <T as Trait>::Bar>(_: T) where T: Trait, <T as Trait>::Bar: Other {}
391            where_clauses.extend(
392                bounds.into_iter().map(|bound| format!("{}: {}", ty, tcx.def_path_str(bound))),
393            );
394        }
395    }
396
397    let generics =
398        if types_str.is_empty() { "".to_string() } else { format!("<{}>", types_str.join(", ")) };
399
400    let where_clauses = if where_clauses.is_empty() {
401        "".to_string()
402    } else {
403        format!(" where {}", where_clauses.join(", "))
404    };
405
406    (generics, where_clauses)
407}
408
409/// Return placeholder code for the given function.
410fn fn_sig_suggestion<'tcx>(
411    tcx: TyCtxt<'tcx>,
412    sig: ty::FnSig<'tcx>,
413    ident: Ident,
414    predicates: impl IntoIterator<Item = (ty::Clause<'tcx>, Span)>,
415    assoc: ty::AssocItem,
416) -> String {
417    let args = sig
418        .inputs()
419        .iter()
420        .enumerate()
421        .map(|(i, ty)| {
422            Some(match ty.kind() {
423                ty::Param(_) if assoc.fn_has_self_parameter && i == 0 => "self".to_string(),
424                ty::Ref(reg, ref_ty, mutability) if i == 0 => {
425                    let reg = format!("{reg} ");
426                    let reg = match &reg[..] {
427                        "'_ " | " " => "",
428                        reg => reg,
429                    };
430                    if assoc.fn_has_self_parameter {
431                        match ref_ty.kind() {
432                            ty::Param(param) if param.name == kw::SelfUpper => {
433                                format!("&{}{}self", reg, mutability.prefix_str())
434                            }
435
436                            _ => format!("self: {ty}"),
437                        }
438                    } else {
439                        format!("_: {ty}")
440                    }
441                }
442                _ => {
443                    if assoc.fn_has_self_parameter && i == 0 {
444                        format!("self: {ty}")
445                    } else {
446                        format!("_: {ty}")
447                    }
448                }
449            })
450        })
451        .chain(std::iter::once(if sig.c_variadic { Some("...".to_string()) } else { None }))
452        .flatten()
453        .collect::<Vec<String>>()
454        .join(", ");
455    let mut output = sig.output();
456
457    let asyncness = if tcx.asyncness(assoc.def_id).is_async() {
458        output = if let ty::Alias(_, alias_ty) = *output.kind()
459            && let Some(output) = tcx
460                .explicit_item_self_bounds(alias_ty.def_id)
461                .iter_instantiated_copied(tcx, alias_ty.args)
462                .find_map(|(bound, _)| {
463                    bound.as_projection_clause()?.no_bound_vars()?.term.as_type()
464                }) {
465            output
466        } else {
467            span_bug!(
468                ident.span,
469                "expected async fn to have `impl Future` output, but it returns {output}"
470            )
471        };
472        "async "
473    } else {
474        ""
475    };
476
477    let output = if !output.is_unit() { format!(" -> {output}") } else { String::new() };
478
479    let safety = sig.safety.prefix_str();
480    let (generics, where_clauses) = bounds_from_generic_predicates(tcx, predicates);
481
482    // FIXME: this is not entirely correct, as the lifetimes from borrowed params will
483    // not be present in the `fn` definition, not will we account for renamed
484    // lifetimes between the `impl` and the `trait`, but this should be good enough to
485    // fill in a significant portion of the missing code, and other subsequent
486    // suggestions can help the user fix the code.
487    format!("{safety}{asyncness}fn {ident}{generics}({args}){output}{where_clauses} {{ todo!() }}")
488}
489
490/// Return placeholder code for the given associated item.
491/// Similar to `ty::AssocItem::suggestion`, but appropriate for use as the code snippet of a
492/// structured suggestion.
493fn suggestion_signature<'tcx>(
494    tcx: TyCtxt<'tcx>,
495    assoc: ty::AssocItem,
496    impl_trait_ref: ty::TraitRef<'tcx>,
497) -> String {
498    let args = ty::GenericArgs::identity_for_item(tcx, assoc.def_id).rebase_onto(
499        tcx,
500        assoc.container_id(tcx),
501        impl_trait_ref.with_self_ty(tcx, tcx.types.self_param).args,
502    );
503
504    match assoc.kind {
505        ty::AssocKind::Fn => fn_sig_suggestion(
506            tcx,
507            tcx.liberate_late_bound_regions(
508                assoc.def_id,
509                tcx.fn_sig(assoc.def_id).instantiate(tcx, args),
510            ),
511            assoc.ident(tcx),
512            tcx.predicates_of(assoc.def_id).instantiate_own(tcx, args),
513            assoc,
514        ),
515        ty::AssocKind::Type => {
516            let (generics, where_clauses) = bounds_from_generic_predicates(
517                tcx,
518                tcx.predicates_of(assoc.def_id).instantiate_own(tcx, args),
519            );
520            format!("type {}{generics} = /* Type */{where_clauses};", assoc.name)
521        }
522        ty::AssocKind::Const => {
523            let ty = tcx.type_of(assoc.def_id).instantiate_identity();
524            let val = tcx
525                .infer_ctxt()
526                .build(TypingMode::non_body_analysis())
527                .err_ctxt()
528                .ty_kind_suggestion(tcx.param_env(assoc.def_id), ty)
529                .unwrap_or_else(|| "value".to_string());
530            format!("const {}: {} = {};", assoc.name, ty, val)
531        }
532    }
533}
534
535/// Emit an error when encountering two or more variants in a transparent enum.
536fn bad_variant_count<'tcx>(tcx: TyCtxt<'tcx>, adt: ty::AdtDef<'tcx>, sp: Span, did: DefId) {
537    let variant_spans: Vec<_> = adt
538        .variants()
539        .iter()
540        .map(|variant| tcx.hir().span_if_local(variant.def_id).unwrap())
541        .collect();
542    let (mut spans, mut many) = (Vec::new(), None);
543    if let [start @ .., end] = &*variant_spans {
544        spans = start.to_vec();
545        many = Some(*end);
546    }
547    tcx.dcx().emit_err(errors::TransparentEnumVariant {
548        span: sp,
549        spans,
550        many,
551        number: adt.variants().len(),
552        path: tcx.def_path_str(did),
553    });
554}
555
556/// Emit an error when encountering two or more non-zero-sized fields in a transparent
557/// enum.
558fn bad_non_zero_sized_fields<'tcx>(
559    tcx: TyCtxt<'tcx>,
560    adt: ty::AdtDef<'tcx>,
561    field_count: usize,
562    field_spans: impl Iterator<Item = Span>,
563    sp: Span,
564) {
565    if adt.is_enum() {
566        tcx.dcx().emit_err(errors::TransparentNonZeroSizedEnum {
567            span: sp,
568            spans: field_spans.collect(),
569            field_count,
570            desc: adt.descr(),
571        });
572    } else {
573        tcx.dcx().emit_err(errors::TransparentNonZeroSized {
574            span: sp,
575            spans: field_spans.collect(),
576            field_count,
577            desc: adt.descr(),
578        });
579    }
580}
581
582// FIXME: Consider moving this method to a more fitting place.
583pub fn potentially_plural_count(count: usize, word: &str) -> String {
584    format!("{} {}{}", count, word, pluralize!(count))
585}
586
587pub fn check_function_signature<'tcx>(
588    tcx: TyCtxt<'tcx>,
589    mut cause: ObligationCause<'tcx>,
590    fn_id: DefId,
591    expected_sig: ty::PolyFnSig<'tcx>,
592) -> Result<(), ErrorGuaranteed> {
593    fn extract_span_for_error_reporting<'tcx>(
594        tcx: TyCtxt<'tcx>,
595        err: TypeError<'_>,
596        cause: &ObligationCause<'tcx>,
597        fn_id: LocalDefId,
598    ) -> rustc_span::Span {
599        let mut args = {
600            let node = tcx.expect_hir_owner_node(fn_id);
601            let decl = node.fn_decl().unwrap_or_else(|| bug!("expected fn decl, found {:?}", node));
602            decl.inputs.iter().map(|t| t.span).chain(std::iter::once(decl.output.span()))
603        };
604
605        match err {
606            TypeError::ArgumentMutability(i)
607            | TypeError::ArgumentSorts(ExpectedFound { .. }, i) => args.nth(i).unwrap(),
608            _ => cause.span,
609        }
610    }
611
612    let local_id = fn_id.as_local().unwrap_or(CRATE_DEF_ID);
613
614    let param_env = ty::ParamEnv::empty();
615
616    let infcx = &tcx.infer_ctxt().build(TypingMode::non_body_analysis());
617    let ocx = ObligationCtxt::new_with_diagnostics(infcx);
618
619    let actual_sig = tcx.fn_sig(fn_id).instantiate_identity();
620
621    let norm_cause = ObligationCause::misc(cause.span, local_id);
622    let actual_sig = ocx.normalize(&norm_cause, param_env, actual_sig);
623
624    match ocx.eq(&cause, param_env, expected_sig, actual_sig) {
625        Ok(()) => {
626            let errors = ocx.select_all_or_error();
627            if !errors.is_empty() {
628                return Err(infcx.err_ctxt().report_fulfillment_errors(errors));
629            }
630        }
631        Err(err) => {
632            let err_ctxt = infcx.err_ctxt();
633            if fn_id.is_local() {
634                cause.span = extract_span_for_error_reporting(tcx, err, &cause, local_id);
635            }
636            let failure_code = cause.as_failure_code_diag(err, cause.span, vec![]);
637            let mut diag = tcx.dcx().create_err(failure_code);
638            err_ctxt.note_type_err(
639                &mut diag,
640                &cause,
641                None,
642                Some(param_env.and(infer::ValuePairs::PolySigs(ExpectedFound {
643                    expected: expected_sig,
644                    found: actual_sig,
645                }))),
646                err,
647                false,
648                None,
649            );
650            return Err(diag.emit());
651        }
652    }
653
654    if let Err(e) = ocx.resolve_regions_and_report_errors(local_id, param_env, []) {
655        return Err(e);
656    }
657
658    Ok(())
659}