diff options
Diffstat (limited to 'compiler/rustc_hir_analysis/src/collect.rs')
| -rw-r--r-- | compiler/rustc_hir_analysis/src/collect.rs | 227 |
1 files changed, 97 insertions, 130 deletions
diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index 7fb024cce5a..ada70117b62 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -38,8 +38,7 @@ use rustc_middle::ty::fold::fold_regions; use rustc_middle::ty::util::{Discr, IntTypeExt}; use rustc_middle::ty::{self, AdtKind, Const, IsSuggestable, Ty, TyCtxt, TypingMode}; use rustc_middle::{bug, span_bug}; -use rustc_span::symbol::{Ident, Symbol, kw, sym}; -use rustc_span::{DUMMY_SP, Span}; +use rustc_span::{DUMMY_SP, Ident, Span, Symbol, kw, sym}; use rustc_trait_selection::error_reporting::traits::suggestions::NextTypeParamName; use rustc_trait_selection::infer::InferCtxtExt; use rustc_trait_selection::traits::ObligationCtxt; @@ -1262,49 +1261,8 @@ fn trait_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::TraitDef { no_dups.then_some(list) }); - let mut deny_explicit_impl = false; - let mut implement_via_object = true; - if let Some(attr) = tcx.get_attr(def_id, sym::rustc_deny_explicit_impl) { - deny_explicit_impl = true; - let mut seen_attr = false; - for meta in attr.meta_item_list().iter().flatten() { - if let Some(meta) = meta.meta_item() - && meta.name_or_empty() == sym::implement_via_object - && let Some(lit) = meta.name_value_literal() - { - if seen_attr { - tcx.dcx().span_err(meta.span, "duplicated `implement_via_object` meta item"); - } - seen_attr = true; - - match lit.symbol { - kw::True => { - implement_via_object = true; - } - kw::False => { - implement_via_object = false; - } - _ => { - tcx.dcx().span_err( - meta.span, - format!( - "unknown literal passed to `implement_via_object` attribute: {}", - lit.symbol - ), - ); - } - } - } else { - tcx.dcx().span_err( - meta.span(), - format!("unknown meta item passed to `rustc_deny_explicit_impl` {meta:?}"), - ); - } - } - if !seen_attr { - tcx.dcx().span_err(attr.span, "missing `implement_via_object` meta item"); - } - } + let deny_explicit_impl = tcx.has_attr(def_id, sym::rustc_deny_explicit_impl); + let implement_via_object = !tcx.has_attr(def_id, sym::rustc_do_not_implement_via_object); ty::TraitDef { def_id: def_id.to_def_id(), @@ -1340,7 +1298,7 @@ fn fn_sig(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<'_, ty::PolyFn .. }) | Item(hir::Item { kind: ItemKind::Fn(sig, generics, _), .. }) => { - infer_return_ty_for_fn_sig(sig, generics, def_id, &icx) + lower_fn_sig_recovering_infer_ret_ty(&icx, sig, generics, def_id) } ImplItem(hir::ImplItem { kind: ImplItemKind::Fn(sig, _), generics, .. }) => { @@ -1357,7 +1315,7 @@ fn fn_sig(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<'_, ty::PolyFn None, ) } else { - infer_return_ty_for_fn_sig(sig, generics, def_id, &icx) + lower_fn_sig_recovering_infer_ret_ty(&icx, sig, generics, def_id) } } @@ -1407,99 +1365,108 @@ fn fn_sig(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<'_, ty::PolyFn ty::EarlyBinder::bind(output) } -fn infer_return_ty_for_fn_sig<'tcx>( - sig: &hir::FnSig<'tcx>, - generics: &hir::Generics<'_>, +fn lower_fn_sig_recovering_infer_ret_ty<'tcx>( + icx: &ItemCtxt<'tcx>, + sig: &'tcx hir::FnSig<'tcx>, + generics: &'tcx hir::Generics<'tcx>, def_id: LocalDefId, +) -> ty::PolyFnSig<'tcx> { + if let Some(infer_ret_ty) = sig.decl.output.get_infer_ret_ty() { + return recover_infer_ret_ty(icx, infer_ret_ty, generics, def_id); + } + + icx.lowerer().lower_fn_ty( + icx.tcx().local_def_id_to_hir_id(def_id), + sig.header.safety, + sig.header.abi, + sig.decl, + Some(generics), + None, + ) +} + +fn recover_infer_ret_ty<'tcx>( icx: &ItemCtxt<'tcx>, + infer_ret_ty: &'tcx hir::Ty<'tcx>, + generics: &'tcx hir::Generics<'tcx>, + def_id: LocalDefId, ) -> ty::PolyFnSig<'tcx> { let tcx = icx.tcx; let hir_id = tcx.local_def_id_to_hir_id(def_id); - match sig.decl.output.get_infer_ret_ty() { - Some(ty) => { - let fn_sig = tcx.typeck(def_id).liberated_fn_sigs()[hir_id]; - // Typeck doesn't expect erased regions to be returned from `type_of`. - // This is a heuristic approach. If the scope has region parameters, - // we should change fn_sig's lifetime from `ReErased` to `ReError`, - // otherwise to `ReStatic`. - let has_region_params = generics.params.iter().any(|param| match param.kind { - GenericParamKind::Lifetime { .. } => true, - _ => false, - }); - let fn_sig = fold_regions(tcx, fn_sig, |r, _| match *r { - ty::ReErased => { - if has_region_params { - ty::Region::new_error_with_message( - tcx, - DUMMY_SP, - "erased region is not allowed here in return type", - ) - } else { - tcx.lifetimes.re_static - } - } - _ => r, - }); + let fn_sig = tcx.typeck(def_id).liberated_fn_sigs()[hir_id]; - let mut visitor = HirPlaceholderCollector::default(); - visitor.visit_ty(ty); - - let mut diag = bad_placeholder(icx.lowerer(), visitor.0, "return type"); - let ret_ty = fn_sig.output(); - // Don't leak types into signatures unless they're nameable! - // For example, if a function returns itself, we don't want that - // recursive function definition to leak out into the fn sig. - let mut recovered_ret_ty = None; - - if let Some(suggestable_ret_ty) = ret_ty.make_suggestable(tcx, false, None) { - diag.span_suggestion( - ty.span, - "replace with the correct return type", - suggestable_ret_ty, - Applicability::MachineApplicable, - ); - recovered_ret_ty = Some(suggestable_ret_ty); - } else if let Some(sugg) = suggest_impl_trait( - &tcx.infer_ctxt().build(TypingMode::non_body_analysis()), - tcx.param_env(def_id), - ret_ty, - ) { - diag.span_suggestion( - ty.span, - "replace with an appropriate return type", - sugg, - Applicability::MachineApplicable, - ); - } else if ret_ty.is_closure() { - diag.help("consider using an `Fn`, `FnMut`, or `FnOnce` trait bound"); - } - // Also note how `Fn` traits work just in case! - if ret_ty.is_closure() { - diag.note( - "for more information on `Fn` traits and closure types, see \ - https://doc.rust-lang.org/book/ch13-01-closures.html", - ); + // Typeck doesn't expect erased regions to be returned from `type_of`. + // This is a heuristic approach. If the scope has region parameters, + // we should change fn_sig's lifetime from `ReErased` to `ReError`, + // otherwise to `ReStatic`. + let has_region_params = generics.params.iter().any(|param| match param.kind { + GenericParamKind::Lifetime { .. } => true, + _ => false, + }); + let fn_sig = fold_regions(tcx, fn_sig, |r, _| match *r { + ty::ReErased => { + if has_region_params { + ty::Region::new_error_with_message( + tcx, + DUMMY_SP, + "erased region is not allowed here in return type", + ) + } else { + tcx.lifetimes.re_static } - - let guar = diag.emit(); - ty::Binder::dummy(tcx.mk_fn_sig( - fn_sig.inputs().iter().copied(), - recovered_ret_ty.unwrap_or_else(|| Ty::new_error(tcx, guar)), - fn_sig.c_variadic, - fn_sig.safety, - fn_sig.abi, - )) } - None => icx.lowerer().lower_fn_ty( - hir_id, - sig.header.safety, - sig.header.abi, - sig.decl, - Some(generics), - None, - ), + _ => r, + }); + + let mut visitor = HirPlaceholderCollector::default(); + visitor.visit_ty(infer_ret_ty); + + let mut diag = bad_placeholder(icx.lowerer(), visitor.0, "return type"); + let ret_ty = fn_sig.output(); + + // Don't leak types into signatures unless they're nameable! + // For example, if a function returns itself, we don't want that + // recursive function definition to leak out into the fn sig. + let mut recovered_ret_ty = None; + if let Some(suggestable_ret_ty) = ret_ty.make_suggestable(tcx, false, None) { + diag.span_suggestion( + infer_ret_ty.span, + "replace with the correct return type", + suggestable_ret_ty, + Applicability::MachineApplicable, + ); + recovered_ret_ty = Some(suggestable_ret_ty); + } else if let Some(sugg) = suggest_impl_trait( + &tcx.infer_ctxt().build(TypingMode::non_body_analysis()), + tcx.param_env(def_id), + ret_ty, + ) { + diag.span_suggestion( + infer_ret_ty.span, + "replace with an appropriate return type", + sugg, + Applicability::MachineApplicable, + ); + } else if ret_ty.is_closure() { + diag.help("consider using an `Fn`, `FnMut`, or `FnOnce` trait bound"); + } + + // Also note how `Fn` traits work just in case! + if ret_ty.is_closure() { + diag.note( + "for more information on `Fn` traits and closure types, see \ + https://doc.rust-lang.org/book/ch13-01-closures.html", + ); } + let guar = diag.emit(); + ty::Binder::dummy(tcx.mk_fn_sig( + fn_sig.inputs().iter().copied(), + recovered_ret_ty.unwrap_or_else(|| Ty::new_error(tcx, guar)), + fn_sig.c_variadic, + fn_sig.safety, + fn_sig.abi, + )) } pub fn suggest_impl_trait<'tcx>( |
