Skip to content

Commit d2d95b8

Browse files
authored
Unrolled build for rust-lang#134259
Rollup merge of rust-lang#134259 - compiler-errors:infer-ret-ty, r=dtolnay Clean up `infer_return_ty_for_fn_sig` The code for lowering fn signatures from HIR currently is structured to prefer the recovery path (where users write `-> _`) over the good path. This PR pulls the recovery code out into a separate fn. Review w/o whitespace
2 parents b57d93d + d82c520 commit d2d95b8

File tree

1 file changed

+94
-85
lines changed

1 file changed

+94
-85
lines changed

compiler/rustc_hir_analysis/src/collect.rs

+94-85
Original file line numberDiff line numberDiff line change
@@ -1340,7 +1340,7 @@ fn fn_sig(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<'_, ty::PolyFn
13401340
..
13411341
})
13421342
| Item(hir::Item { kind: ItemKind::Fn(sig, generics, _), .. }) => {
1343-
infer_return_ty_for_fn_sig(sig, generics, def_id, &icx)
1343+
lower_fn_sig_recovering_infer_ret_ty(&icx, sig, generics, def_id)
13441344
}
13451345

13461346
ImplItem(hir::ImplItem { kind: ImplItemKind::Fn(sig, _), generics, .. }) => {
@@ -1357,7 +1357,7 @@ fn fn_sig(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<'_, ty::PolyFn
13571357
None,
13581358
)
13591359
} else {
1360-
infer_return_ty_for_fn_sig(sig, generics, def_id, &icx)
1360+
lower_fn_sig_recovering_infer_ret_ty(&icx, sig, generics, def_id)
13611361
}
13621362
}
13631363

@@ -1407,99 +1407,108 @@ fn fn_sig(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<'_, ty::PolyFn
14071407
ty::EarlyBinder::bind(output)
14081408
}
14091409

1410-
fn infer_return_ty_for_fn_sig<'tcx>(
1411-
sig: &hir::FnSig<'tcx>,
1412-
generics: &hir::Generics<'_>,
1410+
fn lower_fn_sig_recovering_infer_ret_ty<'tcx>(
1411+
icx: &ItemCtxt<'tcx>,
1412+
sig: &'tcx hir::FnSig<'tcx>,
1413+
generics: &'tcx hir::Generics<'tcx>,
14131414
def_id: LocalDefId,
1415+
) -> ty::PolyFnSig<'tcx> {
1416+
if let Some(infer_ret_ty) = sig.decl.output.get_infer_ret_ty() {
1417+
return recover_infer_ret_ty(icx, infer_ret_ty, generics, def_id);
1418+
}
1419+
1420+
icx.lowerer().lower_fn_ty(
1421+
icx.tcx().local_def_id_to_hir_id(def_id),
1422+
sig.header.safety,
1423+
sig.header.abi,
1424+
sig.decl,
1425+
Some(generics),
1426+
None,
1427+
)
1428+
}
1429+
1430+
fn recover_infer_ret_ty<'tcx>(
14141431
icx: &ItemCtxt<'tcx>,
1432+
infer_ret_ty: &'tcx hir::Ty<'tcx>,
1433+
generics: &'tcx hir::Generics<'tcx>,
1434+
def_id: LocalDefId,
14151435
) -> ty::PolyFnSig<'tcx> {
14161436
let tcx = icx.tcx;
14171437
let hir_id = tcx.local_def_id_to_hir_id(def_id);
14181438

1419-
match sig.decl.output.get_infer_ret_ty() {
1420-
Some(ty) => {
1421-
let fn_sig = tcx.typeck(def_id).liberated_fn_sigs()[hir_id];
1422-
// Typeck doesn't expect erased regions to be returned from `type_of`.
1423-
// This is a heuristic approach. If the scope has region parameters,
1424-
// we should change fn_sig's lifetime from `ReErased` to `ReError`,
1425-
// otherwise to `ReStatic`.
1426-
let has_region_params = generics.params.iter().any(|param| match param.kind {
1427-
GenericParamKind::Lifetime { .. } => true,
1428-
_ => false,
1429-
});
1430-
let fn_sig = fold_regions(tcx, fn_sig, |r, _| match *r {
1431-
ty::ReErased => {
1432-
if has_region_params {
1433-
ty::Region::new_error_with_message(
1434-
tcx,
1435-
DUMMY_SP,
1436-
"erased region is not allowed here in return type",
1437-
)
1438-
} else {
1439-
tcx.lifetimes.re_static
1440-
}
1441-
}
1442-
_ => r,
1443-
});
1439+
let fn_sig = tcx.typeck(def_id).liberated_fn_sigs()[hir_id];
14441440

1445-
let mut visitor = HirPlaceholderCollector::default();
1446-
visitor.visit_ty(ty);
1447-
1448-
let mut diag = bad_placeholder(icx.lowerer(), visitor.0, "return type");
1449-
let ret_ty = fn_sig.output();
1450-
// Don't leak types into signatures unless they're nameable!
1451-
// For example, if a function returns itself, we don't want that
1452-
// recursive function definition to leak out into the fn sig.
1453-
let mut recovered_ret_ty = None;
1454-
1455-
if let Some(suggestable_ret_ty) = ret_ty.make_suggestable(tcx, false, None) {
1456-
diag.span_suggestion(
1457-
ty.span,
1458-
"replace with the correct return type",
1459-
suggestable_ret_ty,
1460-
Applicability::MachineApplicable,
1461-
);
1462-
recovered_ret_ty = Some(suggestable_ret_ty);
1463-
} else if let Some(sugg) = suggest_impl_trait(
1464-
&tcx.infer_ctxt().build(TypingMode::non_body_analysis()),
1465-
tcx.param_env(def_id),
1466-
ret_ty,
1467-
) {
1468-
diag.span_suggestion(
1469-
ty.span,
1470-
"replace with an appropriate return type",
1471-
sugg,
1472-
Applicability::MachineApplicable,
1473-
);
1474-
} else if ret_ty.is_closure() {
1475-
diag.help("consider using an `Fn`, `FnMut`, or `FnOnce` trait bound");
1476-
}
1477-
// Also note how `Fn` traits work just in case!
1478-
if ret_ty.is_closure() {
1479-
diag.note(
1480-
"for more information on `Fn` traits and closure types, see \
1481-
https://doc.rust-lang.org/book/ch13-01-closures.html",
1482-
);
1441+
// Typeck doesn't expect erased regions to be returned from `type_of`.
1442+
// This is a heuristic approach. If the scope has region parameters,
1443+
// we should change fn_sig's lifetime from `ReErased` to `ReError`,
1444+
// otherwise to `ReStatic`.
1445+
let has_region_params = generics.params.iter().any(|param| match param.kind {
1446+
GenericParamKind::Lifetime { .. } => true,
1447+
_ => false,
1448+
});
1449+
let fn_sig = fold_regions(tcx, fn_sig, |r, _| match *r {
1450+
ty::ReErased => {
1451+
if has_region_params {
1452+
ty::Region::new_error_with_message(
1453+
tcx,
1454+
DUMMY_SP,
1455+
"erased region is not allowed here in return type",
1456+
)
1457+
} else {
1458+
tcx.lifetimes.re_static
14831459
}
1484-
1485-
let guar = diag.emit();
1486-
ty::Binder::dummy(tcx.mk_fn_sig(
1487-
fn_sig.inputs().iter().copied(),
1488-
recovered_ret_ty.unwrap_or_else(|| Ty::new_error(tcx, guar)),
1489-
fn_sig.c_variadic,
1490-
fn_sig.safety,
1491-
fn_sig.abi,
1492-
))
14931460
}
1494-
None => icx.lowerer().lower_fn_ty(
1495-
hir_id,
1496-
sig.header.safety,
1497-
sig.header.abi,
1498-
sig.decl,
1499-
Some(generics),
1500-
None,
1501-
),
1461+
_ => r,
1462+
});
1463+
1464+
let mut visitor = HirPlaceholderCollector::default();
1465+
visitor.visit_ty(infer_ret_ty);
1466+
1467+
let mut diag = bad_placeholder(icx.lowerer(), visitor.0, "return type");
1468+
let ret_ty = fn_sig.output();
1469+
1470+
// Don't leak types into signatures unless they're nameable!
1471+
// For example, if a function returns itself, we don't want that
1472+
// recursive function definition to leak out into the fn sig.
1473+
let mut recovered_ret_ty = None;
1474+
if let Some(suggestable_ret_ty) = ret_ty.make_suggestable(tcx, false, None) {
1475+
diag.span_suggestion(
1476+
infer_ret_ty.span,
1477+
"replace with the correct return type",
1478+
suggestable_ret_ty,
1479+
Applicability::MachineApplicable,
1480+
);
1481+
recovered_ret_ty = Some(suggestable_ret_ty);
1482+
} else if let Some(sugg) = suggest_impl_trait(
1483+
&tcx.infer_ctxt().build(TypingMode::non_body_analysis()),
1484+
tcx.param_env(def_id),
1485+
ret_ty,
1486+
) {
1487+
diag.span_suggestion(
1488+
infer_ret_ty.span,
1489+
"replace with an appropriate return type",
1490+
sugg,
1491+
Applicability::MachineApplicable,
1492+
);
1493+
} else if ret_ty.is_closure() {
1494+
diag.help("consider using an `Fn`, `FnMut`, or `FnOnce` trait bound");
1495+
}
1496+
1497+
// Also note how `Fn` traits work just in case!
1498+
if ret_ty.is_closure() {
1499+
diag.note(
1500+
"for more information on `Fn` traits and closure types, see \
1501+
https://doc.rust-lang.org/book/ch13-01-closures.html",
1502+
);
15021503
}
1504+
let guar = diag.emit();
1505+
ty::Binder::dummy(tcx.mk_fn_sig(
1506+
fn_sig.inputs().iter().copied(),
1507+
recovered_ret_ty.unwrap_or_else(|| Ty::new_error(tcx, guar)),
1508+
fn_sig.c_variadic,
1509+
fn_sig.safety,
1510+
fn_sig.abi,
1511+
))
15031512
}
15041513

15051514
pub fn suggest_impl_trait<'tcx>(

0 commit comments

Comments
 (0)