From 7d7b3816607c3f0c5afd4562bb3efca8b6eea777 Mon Sep 17 00:00:00 2001 From: Yuki Okushi Date: Sun, 8 Feb 2026 16:42:28 +0900 Subject: [PATCH 1/3] Fix ICE in borrowck when recovering `fn_sig` for `-> _` --- compiler/rustc_hir_analysis/src/collect.rs | 56 ++++++++++++++++++- tests/crashes/135845.rs | 6 -- .../recover-infer-ret-ty-issue-135845.rs | 11 ++++ .../recover-infer-ret-ty-issue-135845.stderr | 15 +++++ 4 files changed, 80 insertions(+), 8 deletions(-) delete mode 100644 tests/crashes/135845.rs create mode 100644 tests/ui/lifetimes/recover-infer-ret-ty-issue-135845.rs create mode 100644 tests/ui/lifetimes/recover-infer-ret-ty-issue-135845.stderr diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index 03bbc9c0a7c9..29a2e7e36220 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -1138,13 +1138,65 @@ fn recover_infer_ret_ty<'tcx>( ); } let guar = diag.emit(); - ty::Binder::dummy(tcx.mk_fn_sig( + + // If we return a dummy binder here, we can ICE later in borrowck when it encounters + // `ReLateParam` regions (e.g. in a local type annotation) which weren't registered via the + // signature binder. See #135845. + let bound_vars = tcx.late_bound_vars(hir_id); + let scope = def_id.to_def_id(); + + let fn_sig = 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, - )) + ); + + let fn_sig = fold_regions(tcx, fn_sig, |r, _| match r.kind() { + ty::ReLateParam(lp) if lp.scope == scope => { + let br = match lp.kind { + ty::LateParamRegionKind::Anon(idx) | ty::LateParamRegionKind::NamedAnon(idx, _) => { + let idx = idx as usize; + match bound_vars.get(idx).copied() { + Some(ty::BoundVariableKind::Region(br_kind)) => Some(ty::BoundRegion { + var: ty::BoundVar::from_usize(idx), + kind: br_kind, + }), + _ => None, + } + } + ty::LateParamRegionKind::Named(def_id) => { + bound_vars.iter().enumerate().find_map(|(idx, bv)| match bv { + ty::BoundVariableKind::Region( + br_kind @ ty::BoundRegionKind::Named(did), + ) if did == def_id => Some(ty::BoundRegion { + var: ty::BoundVar::from_usize(idx), + kind: br_kind, + }), + _ => None, + }) + } + ty::LateParamRegionKind::ClosureEnv => { + bound_vars.iter().enumerate().find_map(|(idx, bv)| match bv { + ty::BoundVariableKind::Region( + br_kind @ ty::BoundRegionKind::ClosureEnv, + ) => Some(ty::BoundRegion { + var: ty::BoundVar::from_usize(idx), + kind: br_kind, + }), + _ => None, + }) + } + }; + + br.map(|br| ty::Region::new_bound(tcx, ty::INNERMOST, br)) + .unwrap_or_else(|| ty::Region::new_error(tcx, guar)) + } + _ => r, + }); + + ty::Binder::bind_with_vars(fn_sig, bound_vars) } pub fn suggest_impl_trait<'tcx>( diff --git a/tests/crashes/135845.rs b/tests/crashes/135845.rs deleted file mode 100644 index ed038d8a1f18..000000000000 --- a/tests/crashes/135845.rs +++ /dev/null @@ -1,6 +0,0 @@ -//@ known-bug: #135845 -struct S<'a, T: ?Sized>(&'a T); - -fn b<'a>() -> S<'static, _> { - S::<'a>(&0) -} diff --git a/tests/ui/lifetimes/recover-infer-ret-ty-issue-135845.rs b/tests/ui/lifetimes/recover-infer-ret-ty-issue-135845.rs new file mode 100644 index 000000000000..acce49b1af72 --- /dev/null +++ b/tests/ui/lifetimes/recover-infer-ret-ty-issue-135845.rs @@ -0,0 +1,11 @@ +// Regression test for #135845. + +use std::marker::PhantomData; + +fn b<'a>() -> _ { + //~^ ERROR the placeholder `_` is not allowed within types on item signatures for return types [E0121] + let _: PhantomData<&'a ()> = PhantomData; + 0 +} + +fn main() {} diff --git a/tests/ui/lifetimes/recover-infer-ret-ty-issue-135845.stderr b/tests/ui/lifetimes/recover-infer-ret-ty-issue-135845.stderr new file mode 100644 index 000000000000..9f3695e88f82 --- /dev/null +++ b/tests/ui/lifetimes/recover-infer-ret-ty-issue-135845.stderr @@ -0,0 +1,15 @@ +error[E0121]: the placeholder `_` is not allowed within types on item signatures for return types + --> $DIR/recover-infer-ret-ty-issue-135845.rs:5:15 + | +LL | fn b<'a>() -> _ { + | ^ not allowed in type signatures + | +help: replace with the correct return type + | +LL - fn b<'a>() -> _ { +LL + fn b<'a>() -> i32 { + | + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0121`. From 45bc47e4e26f29450dd679c3adac249eae28d220 Mon Sep 17 00:00:00 2001 From: Yuki Okushi Date: Thu, 12 Feb 2026 20:16:33 +0900 Subject: [PATCH 2/3] Apply review suggestions --- compiler/rustc_hir_analysis/src/collect.rs | 106 +++++++++++++-------- 1 file changed, 64 insertions(+), 42 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index 29a2e7e36220..1cd96cf6a54d 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -1063,6 +1063,69 @@ fn lower_fn_sig_recovering_infer_ret_ty<'tcx>( ) } +/// Convert `ReLateParam`s in `value` back into `ReBound`s so the returned +/// `PolyFnSig` properly binds all late-bound vars. +fn late_param_regions_to_bound<'tcx, T>( + tcx: TyCtxt<'tcx>, + scope: DefId, + bound_vars: &'tcx ty::List>, + value: T, +) -> T +where + T: ty::TypeFoldable>, +{ + fold_regions(tcx, value, |r, debruijn| match r.kind() { + ty::ReLateParam(lp) => { + // Should be in scope, otherwise inconsistency happens somewhere. + assert_eq!(lp.scope, scope); + + let br = match lp.kind { + // These variants preserve the bound var index. + kind @ (ty::LateParamRegionKind::Anon(idx) + | ty::LateParamRegionKind::NamedAnon(idx, _)) => { + let idx = idx as usize; + let var = ty::BoundVar::from_usize(idx); + + let Some(ty::BoundVariableKind::Region(kind)) = bound_vars.get(idx).copied() + else { + bug!("unexpected late-bound region {kind:?} for bound vars {bound_vars:?}"); + }; + + ty::BoundRegion { var, kind } + } + + // For named regions, look up the corresponding bound var. + ty::LateParamRegionKind::Named(def_id) => bound_vars + .iter() + .enumerate() + .find_map(|(idx, bv)| match bv { + ty::BoundVariableKind::Region(kind @ ty::BoundRegionKind::Named(did)) + if did == def_id => + { + Some(ty::BoundRegion { var: ty::BoundVar::from_usize(idx), kind }) + } + _ => None, + }) + .unwrap(), + + ty::LateParamRegionKind::ClosureEnv => bound_vars + .iter() + .enumerate() + .find_map(|(idx, bv)| match bv { + ty::BoundVariableKind::Region(kind @ ty::BoundRegionKind::ClosureEnv) => { + Some(ty::BoundRegion { var: ty::BoundVar::from_usize(idx), kind }) + } + _ => None, + }) + .unwrap(), + }; + + ty::Region::new_bound(tcx, debruijn, br) + } + _ => r, + }) +} + fn recover_infer_ret_ty<'tcx>( icx: &ItemCtxt<'tcx>, infer_ret_ty: &'tcx hir::Ty<'tcx>, @@ -1153,48 +1216,7 @@ fn recover_infer_ret_ty<'tcx>( fn_sig.abi, ); - let fn_sig = fold_regions(tcx, fn_sig, |r, _| match r.kind() { - ty::ReLateParam(lp) if lp.scope == scope => { - let br = match lp.kind { - ty::LateParamRegionKind::Anon(idx) | ty::LateParamRegionKind::NamedAnon(idx, _) => { - let idx = idx as usize; - match bound_vars.get(idx).copied() { - Some(ty::BoundVariableKind::Region(br_kind)) => Some(ty::BoundRegion { - var: ty::BoundVar::from_usize(idx), - kind: br_kind, - }), - _ => None, - } - } - ty::LateParamRegionKind::Named(def_id) => { - bound_vars.iter().enumerate().find_map(|(idx, bv)| match bv { - ty::BoundVariableKind::Region( - br_kind @ ty::BoundRegionKind::Named(did), - ) if did == def_id => Some(ty::BoundRegion { - var: ty::BoundVar::from_usize(idx), - kind: br_kind, - }), - _ => None, - }) - } - ty::LateParamRegionKind::ClosureEnv => { - bound_vars.iter().enumerate().find_map(|(idx, bv)| match bv { - ty::BoundVariableKind::Region( - br_kind @ ty::BoundRegionKind::ClosureEnv, - ) => Some(ty::BoundRegion { - var: ty::BoundVar::from_usize(idx), - kind: br_kind, - }), - _ => None, - }) - } - }; - - br.map(|br| ty::Region::new_bound(tcx, ty::INNERMOST, br)) - .unwrap_or_else(|| ty::Region::new_error(tcx, guar)) - } - _ => r, - }); + let fn_sig = late_param_regions_to_bound(tcx, scope, bound_vars, fn_sig); ty::Binder::bind_with_vars(fn_sig, bound_vars) } From b0f2ac8797078dd7a2da924969b57ada41794f7e Mon Sep 17 00:00:00 2001 From: Yuki Okushi Date: Fri, 13 Feb 2026 14:06:30 +0900 Subject: [PATCH 3/3] Return Binder --- compiler/rustc_hir_analysis/src/collect.rs | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index 1cd96cf6a54d..2fc1f1ab01d2 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -1063,18 +1063,17 @@ fn lower_fn_sig_recovering_infer_ret_ty<'tcx>( ) } -/// Convert `ReLateParam`s in `value` back into `ReBound`s so the returned -/// `PolyFnSig` properly binds all late-bound vars. +/// Convert `ReLateParam`s in `value` back into `ReBound`s and bind it with `bound_vars`. fn late_param_regions_to_bound<'tcx, T>( tcx: TyCtxt<'tcx>, scope: DefId, bound_vars: &'tcx ty::List>, value: T, -) -> T +) -> ty::Binder<'tcx, T> where T: ty::TypeFoldable>, { - fold_regions(tcx, value, |r, debruijn| match r.kind() { + let value = fold_regions(tcx, value, |r, debruijn| match r.kind() { ty::ReLateParam(lp) => { // Should be in scope, otherwise inconsistency happens somewhere. assert_eq!(lp.scope, scope); @@ -1123,7 +1122,9 @@ where ty::Region::new_bound(tcx, debruijn, br) } _ => r, - }) + }); + + ty::Binder::bind_with_vars(value, bound_vars) } fn recover_infer_ret_ty<'tcx>( @@ -1216,9 +1217,7 @@ fn recover_infer_ret_ty<'tcx>( fn_sig.abi, ); - let fn_sig = late_param_regions_to_bound(tcx, scope, bound_vars, fn_sig); - - ty::Binder::bind_with_vars(fn_sig, bound_vars) + late_param_regions_to_bound(tcx, scope, bound_vars, fn_sig) } pub fn suggest_impl_trait<'tcx>(