1/*!23# typeck: check phase45Within the check phase of type check, we check each item one at a time6(bodies of function expressions are checked as part of the containing7function). Inference is used to supply types wherever they are unknown.89By far the most complex case is checking the body of a function. This10can be broken down into several distinct phases:1112- gather: creates type variables to represent the type of each local13 variable and pattern binding.1415- main: the main pass does the lion's share of the work: it16 determines the types of all expressions, resolves17 methods, checks for most invalid conditions, and so forth. In18 some cases, where a type is unknown, it may create a type or region19 variable and use that as the type of an expression.2021 In the process of checking, various constraints will be placed on22 these type variables through the subtyping relationships requested23 through the `demand` module. The `infer` module is in charge24 of resolving those constraints.2526- regionck: after main is complete, the regionck pass goes over all27 types looking for regions and making sure that they did not escape28 into places where they are not in scope. This may also influence the29 final assignments of the various region variables if there is some30 flexibility.3132- writeback: writes the final types within a function body, replacing33 type variables with their final inferred types. These final types34 are written into the `tcx.node_types` table, which should *never* contain35 any reference to a type variable.3637## Intermediate types3839While type checking a function, the intermediate types for the40expressions, blocks, and so forth contained within the function are41stored in `fcx.node_types` and `fcx.node_args`. These types42may contain unresolved type variables. After type checking is43complete, the functions in the writeback module are used to take the44types from this table, resolve them, and then write them into their45permanent home in the type context `tcx`.4647This means that during inferencing you should use `fcx.write_ty()`48and `fcx.expr_ty()` / `fcx.node_ty()` to write/obtain the types of49nodes within the function.5051The types of top-level items, which never contain unbound type52variables, are stored directly into the `tcx` typeck_results.5354N.B., a type variable is not the same thing as a type parameter. A55type variable is an instance of a type parameter. That is,56given a generic function `fn foo<T>(t: T)`, while checking the57function `foo`, the type `ty_param(0)` refers to the type `T`, which58is treated in abstract. However, when `foo()` is called, `T` will be59instantiated with a fresh type variable `N`. This variable will60eventually be resolved to some concrete type (which might itself be61a type parameter).6263*/6465pub mod always_applicable;66mod check;67mod compare_eii;68mod compare_impl_item;69mod entry;70pub mod intrinsic;71mod region;72pub mod wfcheck;7374use std::borrow::Cow;75use std::num::NonZero;7677pub use check::{check_abi, check_custom_abi};78use rustc_abi::VariantIdx;79use rustc_data_structures::fx::{FxHashSet, FxIndexMap};80use rustc_errors::{ErrorGuaranteed, pluralize, struct_span_code_err};81use rustc_hir::LangItem;82use rustc_hir::def_id::{DefId, LocalDefId};83use rustc_hir::intravisit::Visitor;84use rustc_index::bit_set::DenseBitSet;85use rustc_infer::infer::{self, TyCtxtInferExt as _};86use rustc_infer::traits::ObligationCause;87use rustc_middle::query::Providers;88use rustc_middle::ty::error::{ExpectedFound, TypeError};89use rustc_middle::ty::print::with_types_for_signature;90use rustc_middle::ty::{91 self, GenericArgs, GenericArgsRef, OutlivesPredicate, Region, Ty, TyCtxt, TypingMode,92 Unnormalized,93};94use rustc_middle::{bug, span_bug};95use rustc_session::errors::feature_err;96use rustc_span::def_id::CRATE_DEF_ID;97use rustc_span::{BytePos, DUMMY_SP, Ident, Span, Symbol, kw, sym};98use rustc_trait_selection::error_reporting::InferCtxtErrorExt;99use rustc_trait_selection::error_reporting::infer::ObligationCauseExt as _;100use rustc_trait_selection::error_reporting::traits::suggestions::ReturnsVisitor;101use rustc_trait_selection::traits::ObligationCtxt;102use tracing::debug;103104use self::compare_impl_item::collect_return_position_impl_trait_in_trait_tys;105use self::region::region_scope_tree;106use crate::{check_c_variadic_abi, errors};107108/// Adds query implementations to the [Providers] vtable, see [`rustc_middle::query`]109pub(super) fn provide(providers: &mut Providers) {110 *providers = Providers {111 adt_destructor,112 adt_async_destructor,113 region_scope_tree,114 collect_return_position_impl_trait_in_trait_tys,115 compare_impl_item: compare_impl_item::compare_impl_item,116 check_coroutine_obligations: check::check_coroutine_obligations,117 check_potentially_region_dependent_goals: check::check_potentially_region_dependent_goals,118 check_type_wf: wfcheck::check_type_wf,119 check_well_formed: wfcheck::check_well_formed,120 ..*providers121 };122}123124fn adt_destructor(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<ty::Destructor> {125 let dtor = tcx.calculate_dtor(def_id, always_applicable::check_drop_impl);126 if dtor.is_none() && tcx.features().async_drop() {127 if let Some(async_dtor) = adt_async_destructor(tcx, def_id) {128 // When type has AsyncDrop impl, but doesn't have Drop impl, generate error129 let span = tcx.def_span(async_dtor.impl_did);130 tcx.dcx().emit_err(errors::AsyncDropWithoutSyncDrop { span });131 }132 }133 dtor134}135136fn adt_async_destructor(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<ty::AsyncDestructor> {137 let result = tcx.calculate_async_dtor(def_id, always_applicable::check_drop_impl);138 // Async drop in libstd/libcore would become insta-stable — catch that mistake.139 if result.is_some() && tcx.features().staged_api() {140 span_bug!(tcx.def_span(def_id), "don't use async drop in libstd, it becomes insta-stable");141 }142 result143}144145/// Given a `DefId` for an opaque type in return position, find its parent item's return146/// expressions.147fn get_owner_return_paths(148 tcx: TyCtxt<'_>,149 def_id: LocalDefId,150) -> Option<(LocalDefId, ReturnsVisitor<'_>)> {151 let hir_id = tcx.local_def_id_to_hir_id(def_id);152 let parent_id = tcx.hir_get_parent_item(hir_id).def_id;153 tcx.hir_node_by_def_id(parent_id).body_id().map(|body_id| {154 let body = tcx.hir_body(body_id);155 let mut visitor = ReturnsVisitor::default();156 visitor.visit_body(body);157 (parent_id, visitor)158 })159}160161pub(super) fn maybe_check_static_with_link_section(tcx: TyCtxt<'_>, id: LocalDefId) {162 // Only restricted on wasm target for now163 if !tcx.sess.target.is_like_wasm {164 return;165 }166167 // If `#[link_section]` is missing, then nothing to verify168 let Some(link_section) = tcx.codegen_fn_attrs(id).link_section else {169 return;170 };171172 // For the wasm32 target statics with `#[link_section]` other than `.init_array`173 // are placed into custom sections of the final output file, but this isn't like174 // custom sections of other executable formats. Namely we can only embed a list175 // of bytes, nothing with provenance (pointers to anything else). If any176 // provenance show up, reject it here.177 // `#[link_section]` may contain arbitrary, or even undefined bytes, but it is178 // the consumer's responsibility to ensure all bytes that have been read179 // have defined values.180 //181 // The `.init_array` section is left to go through the normal custom section code path.182 // When dealing with `.init_array` wasm-ld currently has several limitations. This manifests183 // in workarounds in user-code.184 //185 // * The linker fails to merge multiple items in a crate into the .init_array section.186 // To work around this, a single array can be used placing multiple items in the array.187 // #[link_section = ".init_array"]188 // static FOO: [unsafe extern "C" fn(); 2] = [ctor, ctor];189 // * Even symbols marked used get gc'd from dependant crates unless at least one symbol190 // in the crate is marked with an `#[export_name]`191 //192 // Once `.init_array` support in wasm-ld is complete, the user code workarounds should193 // continue to work, but would no longer be necessary.194195 if let Ok(alloc) = tcx.eval_static_initializer(id.to_def_id())196 && !alloc.inner().provenance().ptrs().is_empty()197 && !link_section.as_str().starts_with(".init_array")198 {199 let msg = "statics with a custom `#[link_section]` must be a \200 simple list of bytes on the wasm target with no \201 extra levels of indirection such as references";202 tcx.dcx().span_err(tcx.def_span(id), msg);203 }204}205206fn 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());214215 let missing_items_msg = missing_items216 .clone()217 .map(|trait_item| trait_item.name().to_string())218 .collect::<Vec<_>>()219 .join("`, `");220221 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 suggest227 // 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 };232233 // Obtain the level of indentation ending in `sugg_sp`.234 let padding = tcx.sess.source_map().indentation_before(sugg_sp).unwrap_or_else(String::new);235 let (mut missing_trait_item, mut missing_trait_item_none, mut missing_trait_item_label) =236 (Vec::new(), Vec::new(), Vec::new());237238 for &trait_item in missing_items {239 let snippet = with_types_for_signature!(suggestion_signature(240 tcx,241 trait_item,242 tcx.impl_trait_ref(impl_def_id).instantiate_identity().skip_norm_wip(),243 ));244 let code = format!("{padding}{snippet}\n{padding}");245 if let Some(span) = tcx.hir_span_if_local(trait_item.def_id) {246 missing_trait_item_label247 .push(errors::MissingTraitItemLabel { span, item: trait_item.name() });248 missing_trait_item.push(errors::MissingTraitItemSuggestion {249 span: sugg_sp,250 code,251 snippet,252 });253 } else {254 missing_trait_item_none.push(errors::MissingTraitItemSuggestionNone {255 span: sugg_sp,256 code,257 snippet,258 })259 }260 }261262 tcx.dcx().emit_err(errors::MissingTraitItem {263 span: tcx.span_of_impl(impl_def_id.to_def_id()).unwrap(),264 missing_items_msg,265 missing_trait_item_label,266 missing_trait_item,267 missing_trait_item_none,268 });269}270271fn missing_items_must_implement_one_of_err(272 tcx: TyCtxt<'_>,273 impl_span: Span,274 missing_items: &[Ident],275 annotation_span: Option<Span>,276) {277 let missing_items_msg =278 missing_items.iter().map(Ident::to_string).collect::<Vec<_>>().join("`, `");279280 tcx.dcx().emit_err(errors::MissingOneOfTraitItem {281 span: impl_span,282 note: annotation_span,283 missing_items_msg,284 });285}286287fn default_body_is_unstable(288 tcx: TyCtxt<'_>,289 impl_span: Span,290 item_did: DefId,291 feature: Symbol,292 reason: Option<Symbol>,293 issue: Option<NonZero<u32>>,294) {295 let missing_item_name = tcx.item_ident(item_did);296 let (mut some_note, mut none_note, mut reason_str) = (false, false, String::new());297 match reason {298 Some(r) => {299 some_note = true;300 reason_str = r.to_string();301 }302 None => none_note = true,303 };304305 let mut err = tcx.dcx().create_err(errors::MissingTraitItemUnstable {306 span: impl_span,307 some_note,308 none_note,309 missing_item_name,310 feature,311 reason: reason_str,312 });313314 let inject_span = item_did.is_local().then(|| tcx.crate_level_attribute_injection_span());315 rustc_session::errors::add_feature_diagnostics_for_issue(316 &mut err,317 &tcx.sess,318 feature,319 rustc_feature::GateIssue::Library(issue),320 false,321 inject_span,322 );323324 err.emit();325}326327/// Re-sugar `ty::GenericPredicates` in a way suitable to be used in structured suggestions.328fn bounds_from_generic_predicates<'tcx>(329 tcx: TyCtxt<'tcx>,330 predicates: impl IntoIterator<Item = (ty::Clause<'tcx>, Span)>,331 assoc: ty::AssocItem,332) -> (String, String) {333 let mut types: FxIndexMap<Ty<'tcx>, Vec<DefId>> = FxIndexMap::default();334 let mut regions: FxIndexMap<Region<'tcx>, Vec<Region<'tcx>>> = 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 ty::ClauseKind::RegionOutlives(OutlivesPredicate(a, b)) => {352 regions.entry(a).or_default().push(b);353 }354 _ => {}355 }356 }357358 let mut where_clauses = vec![];359 let generics = tcx.generics_of(assoc.def_id);360 let params = generics361 .own_params362 .iter()363 .filter(|p| !p.kind.is_synthetic())364 .map(|p| match tcx.mk_param_from_def(p).kind() {365 ty::GenericArgKind::Type(ty) => {366 let bounds =367 types.get(&ty).map(Cow::Borrowed).unwrap_or_else(|| Cow::Owned(Vec::new()));368 let mut bounds_str = vec![];369 for bound in bounds.iter().copied() {370 let mut projections_str = vec![];371 for projection in &projections {372 let p = projection.skip_binder();373 if bound == tcx.parent(p.projection_term.def_id())374 && p.projection_term.self_ty() == ty375 {376 let name = tcx.item_name(p.projection_term.def_id());377 projections_str.push(format!("{} = {}", name, p.term));378 }379 }380 let bound_def_path = if tcx.is_lang_item(bound, LangItem::MetaSized) {381 String::from("?Sized")382 } else {383 tcx.def_path_str(bound)384 };385 if projections_str.is_empty() {386 where_clauses.push(format!("{}: {}", ty, bound_def_path));387 } else {388 bounds_str.push(format!(389 "{}<{}>",390 bound_def_path,391 projections_str.join(", ")392 ));393 }394 }395 if bounds_str.is_empty() {396 ty.to_string()397 } else {398 format!("{}: {}", ty, bounds_str.join(" + "))399 }400 }401 ty::GenericArgKind::Const(ct) => {402 format!("const {ct}: {}", tcx.type_of(p.def_id).skip_binder())403 }404 ty::GenericArgKind::Lifetime(region) => {405 if let Some(v) = regions.get(®ion)406 && !v.is_empty()407 {408 format!(409 "{region}: {}",410 v.into_iter().map(Region::to_string).collect::<Vec<_>>().join(" + ")411 )412 } else {413 region.to_string()414 }415 }416 })417 .collect::<Vec<_>>();418 for (ty, bounds) in types.into_iter() {419 if !matches!(ty.kind(), ty::Param(_)) {420 // Avoid suggesting the following:421 // fn foo<T, <T as Trait>::Bar>(_: T) where T: Trait, <T as Trait>::Bar: Other {}422 where_clauses.extend(423 bounds.into_iter().map(|bound| format!("{}: {}", ty, tcx.def_path_str(bound))),424 );425 }426 }427428 let generics =429 if params.is_empty() { "".to_string() } else { format!("<{}>", params.join(", ")) };430431 let where_clauses = if where_clauses.is_empty() {432 "".to_string()433 } else {434 format!(" where {}", where_clauses.join(", "))435 };436437 (generics, where_clauses)438}439440/// Return placeholder code for the given function.441fn fn_sig_suggestion<'tcx>(442 tcx: TyCtxt<'tcx>,443 sig: ty::FnSig<'tcx>,444 ident: Ident,445 predicates: impl IntoIterator<Item = (ty::Clause<'tcx>, Span)>,446 assoc: ty::AssocItem,447) -> String {448 let args = sig449 .inputs()450 .iter()451 .enumerate()452 .map(|(i, ty)| {453 Some(match ty.kind() {454 ty::Param(_) if assoc.is_method() && i == 0 => "self".to_string(),455 ty::Ref(reg, ref_ty, mutability) if i == 0 => {456 let reg = format!("{reg} ");457 let reg = match ®[..] {458 "'_ " | " " => "",459 reg => reg,460 };461 if assoc.is_method() {462 match ref_ty.kind() {463 ty::Param(param) if param.name == kw::SelfUpper => {464 format!("&{}{}self", reg, mutability.prefix_str())465 }466467 _ => format!("self: {ty}"),468 }469 } else {470 format!("_: {ty}")471 }472 }473 _ => {474 if assoc.is_method() && i == 0 {475 format!("self: {ty}")476 } else {477 format!("_: {ty}")478 }479 }480 })481 })482 .chain(std::iter::once(if sig.c_variadic() { Some("...".to_string()) } else { None }))483 .flatten()484 .collect::<Vec<String>>()485 .join(", ");486 let mut output = sig.output();487488 let asyncness = if tcx.asyncness(assoc.def_id).is_async() {489 output = if let ty::Alias(alias_ty) = *output.kind()490 && let Some(output) = tcx491 .explicit_item_self_bounds(alias_ty.kind.def_id())492 .iter_instantiated_copied(tcx, alias_ty.args)493 .map(Unnormalized::skip_norm_wip)494 .find_map(|(bound, _)| {495 bound.as_projection_clause()?.no_bound_vars()?.term.as_type()496 }) {497 output498 } else {499 span_bug!(500 ident.span,501 "expected async fn to have `impl Future` output, but it returns {output}"502 )503 };504 "async "505 } else {506 ""507 };508509 let output = if !output.is_unit() { format!(" -> {output}") } else { String::new() };510511 let safety = sig.safety().prefix_str();512 let (generics, where_clauses) = bounds_from_generic_predicates(tcx, predicates, assoc);513514 // FIXME: this is not entirely correct, as the lifetimes from borrowed params will515 // not be present in the `fn` definition, nor will we account for renamed516 // lifetimes between the `impl` and the `trait`, but this should be good enough to517 // fill in a significant portion of the missing code, and other subsequent518 // suggestions can help the user fix the code.519 format!("{safety}{asyncness}fn {ident}{generics}({args}){output}{where_clauses} {{ todo!() }}")520}521522/// Return placeholder code for the given associated item.523/// Similar to `ty::AssocItem::suggestion`, but appropriate for use as the code snippet of a524/// structured suggestion.525fn suggestion_signature<'tcx>(526 tcx: TyCtxt<'tcx>,527 assoc: ty::AssocItem,528 impl_trait_ref: ty::TraitRef<'tcx>,529) -> String {530 let args = ty::GenericArgs::identity_for_item(tcx, assoc.def_id).rebase_onto(531 tcx,532 assoc.container_id(tcx),533 impl_trait_ref.with_replaced_self_ty(tcx, tcx.types.self_param).args,534 );535536 match assoc.kind {537 ty::AssocKind::Fn { .. } => fn_sig_suggestion(538 tcx,539 tcx.liberate_late_bound_regions(540 assoc.def_id,541 tcx.fn_sig(assoc.def_id).instantiate(tcx, args).skip_norm_wip(),542 ),543 assoc.ident(tcx),544 tcx.predicates_of(assoc.def_id)545 .instantiate_own(tcx, args)546 .map(|(c, s)| (c.skip_norm_wip(), s)),547 assoc,548 ),549 ty::AssocKind::Type { .. } => {550 let (generics, where_clauses) = bounds_from_generic_predicates(551 tcx,552 tcx.predicates_of(assoc.def_id)553 .instantiate_own(tcx, args)554 .map(|(c, s)| (c.skip_norm_wip(), s)),555 assoc,556 );557 format!("type {}{generics} = /* Type */{where_clauses};", assoc.name())558 }559 ty::AssocKind::Const { name, .. } => {560 let ty = tcx.type_of(assoc.def_id).instantiate_identity().skip_norm_wip();561 let val = tcx562 .infer_ctxt()563 .build(TypingMode::non_body_analysis())564 .err_ctxt()565 .ty_kind_suggestion(tcx.param_env(assoc.def_id), ty)566 .unwrap_or_else(|| "value".to_string());567 format!("const {}: {} = {};", name, ty, val)568 }569 }570}571572/// Emit an error when encountering two or more variants in a transparent enum.573fn bad_variant_count<'tcx>(tcx: TyCtxt<'tcx>, adt: ty::AdtDef<'tcx>, sp: Span, did: DefId) {574 let variant_spans: Vec<_> = adt575 .variants()576 .iter()577 .map(|variant| tcx.hir_span_if_local(variant.def_id).unwrap())578 .collect();579 let (mut spans, mut many) = (Vec::new(), None);580 if let [start @ .., end] = &*variant_spans {581 spans = start.to_vec();582 many = Some(*end);583 }584 tcx.dcx().emit_err(errors::TransparentEnumVariant {585 span: sp,586 spans,587 many,588 number: adt.variants().len(),589 path: tcx.def_path_str(did),590 });591}592593/// Emit an error when encountering two or more non-zero-sized fields in a transparent594/// enum.595fn bad_non_zero_sized_fields<'tcx>(596 tcx: TyCtxt<'tcx>,597 adt: ty::AdtDef<'tcx>,598 field_count: usize,599 field_spans: impl Iterator<Item = Span>,600 sp: Span,601) {602 if adt.is_enum() {603 tcx.dcx().emit_err(errors::TransparentNonZeroSizedEnum {604 span: sp,605 spans: field_spans.collect(),606 field_count,607 desc: adt.descr(),608 });609 } else {610 tcx.dcx().emit_err(errors::TransparentNonZeroSized {611 span: sp,612 spans: field_spans.collect(),613 field_count,614 desc: adt.descr(),615 });616 }617}618619// FIXME: Consider moving this method to a more fitting place.620pub fn potentially_plural_count(count: usize, word: &str) -> String {621 format!("{} {}{}", count, word, pluralize!(count))622}623624pub fn check_function_signature<'tcx>(625 tcx: TyCtxt<'tcx>,626 mut cause: ObligationCause<'tcx>,627 fn_id: DefId,628 expected_sig: ty::PolyFnSig<'tcx>,629) -> Result<(), ErrorGuaranteed> {630 fn extract_span_for_error_reporting<'tcx>(631 tcx: TyCtxt<'tcx>,632 err: TypeError<'_>,633 cause: &ObligationCause<'tcx>,634 fn_id: LocalDefId,635 ) -> rustc_span::Span {636 let mut args = {637 let node = tcx.expect_hir_owner_node(fn_id);638 let decl = node.fn_decl().unwrap_or_else(|| bug!("expected fn decl, found {:?}", node));639 decl.inputs.iter().map(|t| t.span).chain(std::iter::once(decl.output.span()))640 };641642 match err {643 TypeError::ArgumentMutability(i)644 | TypeError::ArgumentSorts(ExpectedFound { .. }, i) => args.nth(i).unwrap(),645 _ => cause.span,646 }647 }648649 let local_id = fn_id.as_local().unwrap_or(CRATE_DEF_ID);650651 let param_env = ty::ParamEnv::empty();652653 let infcx = &tcx.infer_ctxt().build(TypingMode::non_body_analysis());654 let ocx = ObligationCtxt::new_with_diagnostics(infcx);655656 let actual_sig = tcx.fn_sig(fn_id).instantiate_identity();657658 let norm_cause = ObligationCause::misc(cause.span, local_id);659 let actual_sig = ocx.normalize(&norm_cause, param_env, actual_sig);660661 match ocx.eq(&cause, param_env, expected_sig, actual_sig) {662 Ok(()) => {663 let errors = ocx.evaluate_obligations_error_on_ambiguity();664 if !errors.is_empty() {665 return Err(infcx.err_ctxt().report_fulfillment_errors(errors));666 }667 }668 Err(err) => {669 let err_ctxt = infcx.err_ctxt();670 if fn_id.is_local() {671 cause.span = extract_span_for_error_reporting(tcx, err, &cause, local_id);672 }673 let failure_code = cause.as_failure_code_diag(err, cause.span, vec![]);674 let mut diag = tcx.dcx().create_err(failure_code);675 err_ctxt.note_type_err(676 &mut diag,677 &cause,678 None,679 Some(param_env.and(infer::ValuePairs::PolySigs(ExpectedFound {680 expected: expected_sig,681 found: actual_sig,682 }))),683 err,684 false,685 None,686 );687 return Err(diag.emit());688 }689 }690691 if let Err(e) = ocx.resolve_regions_and_report_errors(local_id, param_env, []) {692 return Err(e);693 }694695 Ok(())696}