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