Clean up infer_return_ty_for_fn_sig
This commit is contained in:
parent
4847d6a9d0
commit
d82c520f14
1 changed files with 95 additions and 86 deletions
|
@ -1330,7 +1330,7 @@ fn fn_sig(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<'_, ty::PolyFn
|
||||||
..
|
..
|
||||||
})
|
})
|
||||||
| Item(hir::Item { kind: ItemKind::Fn(sig, generics, _), .. }) => {
|
| 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, .. }) => {
|
ImplItem(hir::ImplItem { kind: ImplItemKind::Fn(sig, _), generics, .. }) => {
|
||||||
|
@ -1347,7 +1347,7 @@ fn fn_sig(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<'_, ty::PolyFn
|
||||||
None,
|
None,
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
infer_return_ty_for_fn_sig(sig, generics, def_id, &icx)
|
lower_fn_sig_recovering_infer_ret_ty(&icx, sig, generics, def_id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1397,99 +1397,108 @@ fn fn_sig(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<'_, ty::PolyFn
|
||||||
ty::EarlyBinder::bind(output)
|
ty::EarlyBinder::bind(output)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn infer_return_ty_for_fn_sig<'tcx>(
|
fn lower_fn_sig_recovering_infer_ret_ty<'tcx>(
|
||||||
sig: &hir::FnSig<'tcx>,
|
|
||||||
generics: &hir::Generics<'_>,
|
|
||||||
def_id: LocalDefId,
|
|
||||||
icx: &ItemCtxt<'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> {
|
) -> ty::PolyFnSig<'tcx> {
|
||||||
let tcx = icx.tcx;
|
let tcx = icx.tcx;
|
||||||
let hir_id = tcx.local_def_id_to_hir_id(def_id);
|
let hir_id = tcx.local_def_id_to_hir_id(def_id);
|
||||||
|
|
||||||
match sig.decl.output.get_infer_ret_ty() {
|
let fn_sig = tcx.typeck(def_id).liberated_fn_sigs()[hir_id];
|
||||||
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 mut visitor = HirPlaceholderCollector::default();
|
// Typeck doesn't expect erased regions to be returned from `type_of`.
|
||||||
visitor.visit_ty(ty);
|
// This is a heuristic approach. If the scope has region parameters,
|
||||||
|
// we should change fn_sig's lifetime from `ReErased` to `ReError`,
|
||||||
let mut diag = bad_placeholder(icx.lowerer(), visitor.0, "return type");
|
// otherwise to `ReStatic`.
|
||||||
let ret_ty = fn_sig.output();
|
let has_region_params = generics.params.iter().any(|param| match param.kind {
|
||||||
// Don't leak types into signatures unless they're nameable!
|
GenericParamKind::Lifetime { .. } => true,
|
||||||
// For example, if a function returns itself, we don't want that
|
_ => false,
|
||||||
// recursive function definition to leak out into the fn sig.
|
});
|
||||||
let mut recovered_ret_ty = None;
|
let fn_sig = fold_regions(tcx, fn_sig, |r, _| match *r {
|
||||||
|
ty::ReErased => {
|
||||||
if let Some(suggestable_ret_ty) = ret_ty.make_suggestable(tcx, false, None) {
|
if has_region_params {
|
||||||
diag.span_suggestion(
|
ty::Region::new_error_with_message(
|
||||||
ty.span,
|
tcx,
|
||||||
"replace with the correct return type",
|
DUMMY_SP,
|
||||||
suggestable_ret_ty,
|
"erased region is not allowed here in return type",
|
||||||
Applicability::MachineApplicable,
|
)
|
||||||
);
|
} else {
|
||||||
recovered_ret_ty = Some(suggestable_ret_ty);
|
tcx.lifetimes.re_static
|
||||||
} 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",
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
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(
|
_ => r,
|
||||||
hir_id,
|
});
|
||||||
sig.header.safety,
|
|
||||||
sig.header.abi,
|
let mut visitor = HirPlaceholderCollector::default();
|
||||||
sig.decl,
|
visitor.visit_ty(infer_ret_ty);
|
||||||
Some(generics),
|
|
||||||
None,
|
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>(
|
pub fn suggest_impl_trait<'tcx>(
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue